Joi validation set default as empty object - hapi.js

I'm running into an issue (or what I believe to be one) with Joi validation. I'm trying to assign a value to a non-existent key if it's been passed as part of the request body.
So for example:
parameters: Joi.object().keys({
keyA: Joi.string().allow('').allow(null).default(null),
keyB: Joi.object().keys({
b1: Joi.string(),
b2: Joi.string(),
b3: Joi.object().keys({
b3_1: Joi.string(),
b3_2: Joi.string(),
b3_3: Joi.string()
})
}).default({}),
keyC: Joi.object().keys({
c1: Joi.number(),
c2: Joi.number(),
c3: Joi.boolean(),
c4: Joi.boolean()
}).default({}),
keyD: Joi.object().keys({
d1: Joi.number(),
d2: Joi.number()
}).default({}),
keyE: Joi.object().keys({
e1: Joi.number()
}).default({})
}).allow(null)
So to be specific if I were to pass in:
{
keyA: "foo",
keyD: {
d1: 21.9,
d2: 21.1
},
keyE: {
e1: 42
}
}
I would get this in return
{
keyA: "foo",
keyB: {},
keyC: {},
keyD: {
d1: 21.9,
d2: 21.1
},
keyE: {
e1: 42
}
}
With :eyes: on the empty objects. What am I missing with the Joi.default() method? Am I overextending what Joi is meant for?

I'll start by pointing out that the schema in your question isn't valid JavaScript, you've closed a few too many brackets before declaring the rule for keyC. I'll assume this is simply a formatting error with the question and your actual schema is currently valid.
Secondly, there's nothing wrong with how you've declared your defaults.. it works just fine. I'll assume it's the way you're validating the schema which is the problem.
Try running this. I've mimicked the validation method in the docs for default().
const schema = Joi.object().keys({
keyA: Joi.string().allow('').allow(null).default(null),
keyB: Joi.object().keys({
b1: Joi.string(),
b2: Joi.string(),
b3: Joi.object().keys({
b3_1: Joi.string(),
b3_2: Joi.string(),
b3_3: Joi.string()
})
}).default({}),
keyC: Joi.object().keys({
c1: Joi.number(),
c2: Joi.number(),
c3: Joi.boolean(),
c4: Joi.boolean()
}).default({}),
keyD: Joi.object().keys({
d1: Joi.number(),
d2: Joi.number()
}).default({}),
keyE: Joi.object().keys({
e1: Joi.number()
}).default({})
}).allow(null);
Joi.validate({
keyA: "foo",
keyD: {
d1: 21.9,
d2: 21.1
},
keyE: {
e1: 42
}
}, schema, (err, value) =>
{
if (err)
throw err;
console.log(value);
});
I get this in the console:
{
keyA :'foo',
keyD: {
d1: 21.9,
d2: 21.1
},
keyE: {
e1: 42
},
keyB: {},
keyC: {}
}
The keys are unlikely to look ordered like your expected output, but that shouldn't matter as object keys are not ordered anyway.

You can set the default values, you should try this:
parameters: Joi.object().keys({
keyA: Joi.string().allow(null).default(null),
keyB: Joi.object().keys({
b1: Joi.string().default("abc"),
b2: Joi.string().default("abc"),
b3: Joi.object().keys({
b3_1: Joi.string().default("abc"),
b3_2: Joi.string().default("abc"),
b3_3: Joi.string().default("abc")
})
})
}).default({}),
keyC: Joi.object().keys({
c1: Joi.number().default(0),
c2: Joi.number().default(0),
c3: Joi.boolean().default(0),
c4: Joi.boolean().default(0)
}).default({}),
keyD: Joi.object().keys({
d1: Joi.number().default(0),
d2: Joi.number().default(0)
}).default({}),
keyE: Joi.object().keys({
e1: Joi.number().default(0)
}).default({})
}).allow(null)

Related

Parsing Dynamic response in Karate

I want to verify the value of "RequestedName" in the following response, where the keys for different drugs is dynamic:
{
"requestId": "c826bee1-610e-4dee-b998-1fe4f8c15a1b",
"requestSource": "",
"responseSource": "client",
"status": 200,
"responseCodes": [
{
"code": "S00001",
"message": "Success.",
"params": {
"entity": ""
}
}
],
"context": null,
"payload": {
"0113ccf86ba79b698b8e7a8fb9effc4b": {
"RequestedName": "paracetamol",
"SearchKey": "0113ccf86ba79b698b8e7a8fb9effc4b",
"Name": "Genexa Acetaminophen Extra Strength",
"PrescribableName": "",
"ProductCodes": [
"69676-0059"
],
"DosageForm": "Tablet, coated",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0349fa4ea29da419c46745bc7e2a6c07": {
"RequestedName": "paracetamol",
"SearchKey": "0349fa4ea29da419c46745bc7e2a6c07",
"Name": "Pain Reliever",
"PrescribableName": "",
"ProductCodes": [
"70677-0168"
],
"DosageForm": "Tablet, extended release",
"Route": "Oral",
"Approved": true,
"UnApproved": false,
"Generic": true,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "650",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"060cfbde5d82d947c56aac304c136fd3": {
"RequestedName": "paracetamol",
"SearchKey": "060cfbde5d82d947c56aac304c136fd3",
"Name": "Betr Pain Relief",
"PrescribableName": "Acetaminophen 500 mg Oral Tablet",
"ProductCodes": [
"80267-0484"
],
"DosageForm": "Tablet",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0950fcbac262c1c1d3a9e6630615a5f9": {
"RequestedName": "paracetamol",
"SearchKey": "0950fcbac262c1c1d3a9e6630615a5f9",
"Name": "Acetaminophen",
I tired this:
* def list = []
* def fun = function(k, v){ karate.appendTo('list', { key: k, val: v } )}
* karate.forEach(response, fun)
* def keys = $list[?(#.val.payload.RequestedName==drugName)].key
but not working, getting error as below:
def keys = $list[?(#.val.payload.RequestedName==drugName)].key
Failed to parse filter: [?(#.val.payload.RequestedName==drugName)], error on position: 32, char: d
testsuite/GetDrugs.feature:20
Here is the approach you can use:
* def response =
"""
{
dynamicKey1: {
fixedKey: 'fixedValue1',
dataKey: 'dataValue2'
},
dynamicKey2: {
fixedKey: 'fixedValue2',
dataKey: 'dataValue2'
}
}
"""
* def keys = []
* def fun = function(k, v){ if (v.fixedKey == 'fixedValue2') keys.push(k) }
* karate.forEach(response, fun)
* match keys == ['dynamicKey2']

how can I loop through the payload and search within the same payload in another array with similar structure and alter matches

I have entered the payload as shown below, but I have to replace the values โ€‹โ€‹of "labelnumber" with the similar number from the main line array with the matches "payload.lines.number = payload.notification.body.lines.number" that are inside the line array inside the notification element, can anyone help me how can we replace it.
input payload
{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
],
"notification":{
"body":{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "123",
"labelnumber":"",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "456",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
}
]
}
}
}
expected payload
{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
],
"notification":{
"body":{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
]
}
}
}
As you can see in this example, I need to loop through the main row array and find the matches within the notification array and assign the corresponding value.
NOTE: maybe in the notification.body has many elements and I don't need to change them and I don't know the name of its elements, in this case it only has "date" but I need to keep them as they are.
With the update operator you can update only the keys that you want. This solution assumes that all the number values are defined in payload.lines.
%dw 2.0
output application/json
---
payload update {
case lines at .notification.body.lines -> lines map ((item, index) ->
item update {
case .labelnumber -> (payload.lines filter ($.number == item.number))[0].labelnumber
}
)
}
Converting reference line Array to Hashmap will help replace values efficiently instead of looping every time. Following code will work
%dw 2.0
output application/json
var lineMap = {(payload.lines map {
($.number) : $.labelnumber
})}
var modifiedLines = (payload.notification.body.lines map ((item, index) -> {
data : item mapObject ((value, key, dataindex) -> {
(key) : if (key ~= 'labelnumber') lineMap[item.number] else value
})
})).data
---
(payload - 'notification') ++
{
"notification":{
"body":{
"lines": modifiedLines
}
}
}
Update : with updated requirement body can have any fields
%dw 2.0
import * from dw::util::Values
output application/json
var lineMap = {(payload.lines map {
($.number) : $.labelnumber
})}
var modifiedLines = payload.notification.body.lines map ((item, index) -> item update 'labelnumber' with lineMap[item.number])
var body = (payload.notification.body - 'lines') ++ {lines : modifiedLines}
---
(payload - 'notification') ++
{
"notification":{
"body": body
}
}

Why i cant delete data from arrays more than one? React Native

I want to delete item from array object base of selected checkboxes. But when I try to delete by id, it's only delete one object.
const [datas, setData] = useState([]); <-- i already setData(Data)
const deleteItemById = (id) => { << ----------- Something wrong with this code
const filteredData = datas.filter(item => item.id !== id);
setData(filteredData);
console.log(datas)
}
const selectedID = () =>{
--- Some API Post Method ---
--- example id_kunjungan is array and contain ["1","2"] from selected checbox
for (var i = 0; i < id_kunjungan.length; i++){
deleteItemById(id_kunjungan?.[i]) <<------- this return the id
console.log(id_kunjungan?.[i])
}
}
const Data= [
{
"start": "2022-01-01 10:35:08",
"id": "1",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "2",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "3",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "4",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
];
I already check for loop its run 2 times but the id[2] is not deleted, it only deletes the first id, not the second or third or more. Why this is happened? Or what is wrong with my code?
This is your code and you are using a for-loop to update the state, which mean states may not be updated correctly since you are updating states many times at one go, overwriting each update.
// This code is wrong โŒ
for (var i = 0; i < id_kunjungan.length; i++){
deleteItemById(id_kunjungan?.[i]) // you are calling setDatas multiple times here which is wrong.
console.log(id_kunjungan?.[i])
}
You can try doing just
deleteItemByIds(id_kunjungan) // <--- send the entire array of Ids
Then modify your deleteItemByIds function to remove all items whose id matches.
const deleteItemByIds = (ids = []) => { // <<-- array of ids e.g. [1,2,3,4,5]
const filteredData = datas.filter(item => !ids.includes(item.id);
setData(filteredData);
// console.log(datas) // <--- โŒ Remove this. this will not give u the latest state because state updating is async
}
If you want to see the state change, add a useEffect block.
useEffect(() => {
console.log('datas', datas); //console log whenever datas changes.
}, [datas])
Try this
const Data= [
{
"start": "2022-01-01 10:35:08",
"id": "1",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "2",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "3",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
{
"start": "2022-01-01 10:35:08",
"id": "4",
"tanggal": "01-01-2022",
"hari": "Saturday",
},
];
const deleteItems = (idsToDelete) => {
const newData = Data.filter((item) => {
return !idsToDelete.includes(item.id)
})
return newData
}
console.log(deleteItems(['1','2'])) // <--- pass the ids to delete here
Using Splice make it easier. Using id for finding index of array, and splice it.
const deleteItemById = (id) => {
setData((prevState) =>{
const index = prevState.map(function(x) {return x.id; }).indexOf(id);
const filteredData = prevState.splice(index, 1);
return [...prevState]
})
}

Convert array of json into single json with inner array

I'm getting a message from a system in json format and want to perform a transformation in order to get below message
Source message:
[
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": "2019-01-03T22:00:00",
"BATCH_ID": 1812,
"STORENUMBER": 1197,
"PROCESS_STATUS": "P"
},
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": "2019-01-04T18:00:00",
"BATCH_ID": 1812,
"STORENUMBER": 1197,
"PROCESS_STATUS": "P"
},
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": "2019-01-03T22:00:00",
"BATCH_ID": 1314,
"STORENUMBER": 1198,
"PROCESS_STATUS": "P"
},
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": "2019-01-04T18:00:00",
"BATCH_ID": 1314,
"STORENUMBER": 1198,
"PROCESS_STATUS": "P"
}]
Expected Output
[
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": ["2019-01-03T22:00:00","2019-01-04T18:00:00"],
"BATCH_ID": 1812,
"STORENUMBER": 1197,
"PROCESS_STATUS": "P"
},
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": ["2019-01-03T22:00:00","2019-01-04T18:00:00"],
"BATCH_ID": 1812,
"STORENUMBER": 1198,
"PROCESS_STATUS": "P"
}]
I'm new to dataweave and tried using map but not able to understand how to achieve result.
Try the following in dataweave:
%dw 1.0
%output application/json
%var time=(payload map $.STORE_CLOSING_TIME) distinctBy $.STORE_CLOSING_TIME
---
(payload map {
"OPERATING_COMPANY": $.OPERATING_COMPANY,
"STORE_CLOSING_TIME": time,
"BATCH_ID": $.BATCH_ID,
"STORENUMBER": $.STORENUMBER,
"PROCESS_STATUS": $.PROCESS_STATUS
}) distinctBy $.STORENUMBER
output:
[
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": [
"2019-01-03T22:00:00",
"2019-01-04T18:00:00"
],
"BATCH_ID": 1812,
"STORENUMBER": 1197,
"PROCESS_STATUS": "P"
},
{
"OPERATING_COMPANY": "xx",
"STORE_CLOSING_TIME": [
"2019-01-03T22:00:00",
"2019-01-04T18:00:00"
],
"BATCH_ID": 1314,
"STORENUMBER": 1198,
"PROCESS_STATUS": "P"
}
]

Mulesoft Joining Arrays that occur one after another in a loop

I'm fairly new to mulesoft, kindly help me with this one.
I'm having a http component in a for each loop,
for the first iteration it gives a payload like:
[
{
"Value1": "xxxx",
"Value2": "yyyy",
"Value3": "zzzz"
},
{
"Value1": "qqqq",
"Value2": "eeee",
"Value3": "rrrr"
}
]
and I'm storing this payload in a variable "var1"
for the second iteration it gives a payload like:
[
{
"Value1": "1234",
"Value2": "5678",
"Value3": "0987"
},
{
"Value1": "qqqq",
"Value2": "5yy4",
"Value3": "9jf7"
}
]
I need to combine them in a way that the result should be
[
{
"Value1": "xxxx",
"Value2": "yyyy",
"Value3": "zzzz"
},
{
"Value1": "qqqq",
"Value2": "eeee",
"Value3": "rrrr"
},
{
"Value1": "1234",
"Value2": "5678",
"Value3": "0987"
},
{
"Value1": "qqqq",
"Value2": "5yy4",
"Value3": "9jf7"
}
]
and store it in a variable, so that I can call it to set payload outside the for each loop.
Thank you for the help !!
You can make use of expression transformer to concat the two Vars.
If you want to do any more operations make use of Dataweave like below
flatten <listOfLists> => <mergedList>