Ember: Must include an 'id' in an object passed to 'push' - serialization

Currently experiencing the following error: You must include an 'id' for failed-shotlist in an object passed to 'push'. This is in a code base I have inherited mid-development and I am fairly new to Ember.
From what I understand, this occurs when the backend does not respond with an ID. The server payload looks like the following (returning an alert object with an embedded failedShotlist record):
alertAuthor: "Test name"
alertDate:"2018-06-28T16:25:21+12:00"
alertIdentifier:"456e15c7-7a8b-11e8-84a8-06f4aef780e3"
alertType:"failedShotlist"
email:"test#gmail.com"
failedShotlist:
projectIdentifier:"79050dfb-5faf-11e8-84a8-06f4aef780e3"
projectName:"8888 st"
projectRoleENUM:"bp"
projectRoleName:"Building Participant"
shotlistDescription:"Framing"
shotlistIdentifier:"79d52773-5faf-11e8-84a8-06f4aef780e3"
inviteIdentifier:null
profileId:"c4e02bee-3d26-11e8-84a8-06f4aef780e3"
shotlistIdentifier:"79d52773-5faf-11e8-84a8-06f4aef780e3"
Since the backend doesn't respond with an ID attr, the primary key needs to be transformed using a serializer's 'primaryKey' property:
serializers/alert.js
export default ApplicationSerializer.extend(EmbeddedRecordsMixin, {
primaryKey: 'alertIdentifier',
attrs: {
'invite': { deserialize: 'records' },
'failedShotlist': { deserialize: 'records' },
},
});
I couldn't find any mention of this, but I assume that embedded records are further serialized by their own serializers. The existing one is as follows:
serializers/failedShotlist.js
export default ApplicationSerializer.extend({
attrs: {
'shotlistId': { key: 'shotlistIdentifier' },
'projectId': { key: 'projectIdentifier' },
},
});
Since the ID's for the failedShotlist object also need to be transformed, I have updated this to include the primaryKey prop:
serializers/failedShotlist.js
export default ApplicationSerializer.extend({
primaryKey: 'shotlistIdentifier',
attrs: {
'shotlistId': { key: 'shotlistIdentifier' },
'projectId': { key: 'projectIdentifier' },
},
});
Unfortunately, this results in the same error I originally encountered. Any ideas as to how this might be resolved?

Something I had overlooked was that the source files for the adapter and the serializer weren't following the naming convention of the rest of the codebase.
Where the serializer was called failedShotlist.js, the model related to it was called failed-shotlist.js.
Renaming the serializer file to failed-shotlist.js allowed my existing code to work:
export default ApplicationSerializer.extend({
primaryKey: 'shotlistIdentifier'
}

Related

JSON Object validation with JSONSchema Validator

const Validator = require('jsonschema').Validator;
const validator = new Validator();
const obj =
[
{
"id":"1",
"firstname":"Jack"
}
];
const instance= {
properties: {
id: {
type: 'number'
},
firstname: {
type: 'string'
}
},
required: ['id', 'firstname'],
additionalProperties: false
};
const result = validator.validate(obj, instance);
console.log(result.errors);
I want to validate a JSON Object using jsonschema Validator. when json object is not as per schema, then also validate function is not returning any error. irrespective of obj being as per schema/instance or not, its error section always returning null.
You've defined obj as an array as opposed to an object. As a result, validation is passing because you've used JSON Schema keywords which only apply to objects. (Many JSON Schema keywords are only applicable to specific types.)
In your schema, add "type": "object", and you should see an error when the instance is not an object.
On a side note, an "instance" is the data you want to validate, and a "schema" is the JSON Schema you want to use for validation.

Ember.js - Accessing nested data via serializer

What is the best approach for accessing a single nested record in Ember?
The JSON response which we are trying to manipulate looks gets returned as the following: (the attribute being targeted is the tradeIdentifier property)
trade:
tradeIdentifier:"83f3f561-62af-11e7-958b-028c04d7e8f9"
tradeName:"Plumber"
userEmail:"test#gmail.com"
The project-user model looks partially like:
email: attr('string'),
trade:attr(),
tradeId: attr(),
The project-user serializer looks partially like:
export default UndefinedOmitted.extend(EmbeddedRecordsMixin, {
primaryKey: 'userRoleId',
attrs: {
'email': { key: 'userEmail' },
'trade': { key: 'trade' },
'tradeId': { key: 'tradeIdentifier' },
},
});
The trade attr here is a placeholder to make sure that the data was accessible.
I would like to be able to access the tradeIdentifier without having to do the following in the component:
const trade = get(formRole, 'trade');
if (trade) {
set(formProps, 'tradeId', trade.tradeIdentifier);
}
Have tested creating a trade-id transform (referenced via tradeId: attr('trade-id')), however to no avail.
export default Transform.extend({
deserialize(val) {
const trade = val;
const tradeId = val.tradeIdentifier;
return tradeId;
},
serialize(val) {
return val;
},
});
Can anyone suggest where I'm going wrong?
A transform seems a bit overkill for what I'm trying to achieve here, however it does the job. Managed to get it working by modifying the following:
In serializers/project-user.js:
'tradeId': { key: 'trade' },
Note that this references the property in the payload to transform, not the property being targeted (which was my mistake).
In models/project-user.js:
tradeId: attr('trade-id'),
Attribute references the transform.
In transform/trade-id.js:
export default Transform.extend({
deserialize(val) {
let tradeId = val
if (tradeId) {
tradeId = val.tradeIdentifier;
}
return tradeId;
},
serialize(val) {
return val;
},
});
If there's a simpler solution outside of transforms, I would still be open to suggestions.

Validation of fetched data from API Redux React

So, I will go straight to the point. I am getting such data from api:
[
{
id: 123,
email: asd#asd.com
},
{
id: 456,
email: asdasd.com
},
{
id: 789,
email: asd#asd
},
...
]
and I should validate email and show this all info in a list, something like this:
asd#asd.com - valid
asdasd.com - invalid
asd#asd - invalid
...
My question is what is the best way to store validation data in a store? Is it better to have something like "isValid" property by each email? I mean like this:
store = {
emailsById: [
123: {
value: asd#asd.com,
isValid: true
},
456: {
value: asdasd.com,
isValid: false
},
789: {
value: asd#asd,
isValid: false
}
...
]
}
or something like this:
store = {
emailsById: [
123: {
value: asd#asd.com
},
456: {
value: asdasd.com
},
789: {
value: asd#asd
}
...
],
inValidIds: ['456', '789']
}
which one is better? Or maybe there is some another better way to have such data in store? Have in mind that there can be thousands emails in a list :)
Thanks in advance for the answers ;)
I recommend reading the article "Avoiding Accidental Complexity When Structuring Your App State" by Tal Kol which answers exactly your problem: https://hackernoon.com/avoiding-accidental-complexity-when-structuring-your-app-state-6e6d22ad5e2a
Your example is quite simplistic and everything really depends on your needs but personally I would go with something like this (based on linked article):
var store = {
emailsById: {
123: {
value: '123#example.com',
},
456: {
value: '456#example.com',
},
789: {
value: '789#example.com',
},
// ...
},
validEmailsMap: {
456: true, // true when valid
789: false, // false when invalid
},
};
So your best option would be to create a separate file that will contain all your validations methods. Import that into the component you're using and then when you want to use the logic for valid/invalid.
If its something that you feel you want to put in the store from the beginning and the data will never be in a transient state you could parse your DTO through an array map in your reducer when you get the response from your API.
export default function (state = initialState, action) {
const {type, response} = action
switch (type) {
case DATA_RECIEVED_SUCCESS:
const items = []
for (var i = 0; i < response.emailsById.length; i++) {
var email = response.emailsById[i];
email.isValid = checkEmailValid(email)
items.push(email)
}
return {
...state,
items
}
}
}
However my preference would be to always check at the last moment you need to. It makes it a safer design in case you find you need to change you design in the future. Also separating the validation logic out will make it more testable
First of all, the way you defined an array in javascript is wrong.
What you need is an array of objects like,
emails : [
{
id: '1',
email: 'abc#abc.com',
isValid: true
},
{
id: '2',
email: 'abc.com',
isValid: false;
}
];
if you need do access email based on an id, you can add an id property along with email and isValid. uuid is a good way to go about it.
In conclusion, it depends upon your use case.
I believe, the above example is a good way to keep data in store because it's simple.
What you described in your second example is like maintaining two different states. I would not recommend that.

hapijs joi validation , just validate one field and to allow any field

I want to validate one field and to allow another fields without validation; by example just to validate: "firstname" field. In my code when I comment 'payload', hapi allow me to record any field, when I uncomment 'payload' hapijs dont allow me record any field, but I want just to validate by example 'firstname' to be a 'string' and let rest of fields to allow. I plan to have variable fields accord a database config, so I'm going to just validate some fixed fields and let to save another variable fields controlled in the front end, not in the backend
config: {
validate: {
/* payload: {
firstname: Joi.string(),
lastname: Joi.string()
...anothers fields...
}*/
}
}
UPDATED:
thanks to Robert K. Bell, i've adapted the solution is to add 'validate':
config: {
validate: {
options: {
allowUnknown: true
},
payload: {
firstname: Joi.string()
}
}
}
You may be looking for the .unknown() method:
object.unknown([allow])
Overrides the handling of unknown keys for the scope of the current object only (does not apply to children) where:
allow - if false, unknown keys are not allowed, otherwise unknown keys are ignored.
js
const schema = Joi.object({ a: Joi.any() }).unknown();
config: {
validate: {
payload: Joi.object({
'firstname': Joi.string(),
}).options({ allowUnknown: true })
}
}
Instead of adding validation fields in the validate validate the payload directly using Joi object. Which accepts allowUnknown true using this it will only validated only the fields which are mentioned in the Joi Object.
.... {allowUnknown: true}
as per doc, there is "options" method can be used while creating Joi objectSchema.
i.e. tobe very simple UI can send many keys but use only 2 keys email, and password. so a validation function can be defined as this.
function validateUserForSubscription(input) {
const schema = Joi.object({
email: Joi.string().min(5).max(255).required().email(),
password: Joi.string().min(5).max(1024).required()
}).options({ allowUnknown: true });
return schema.validate(input);
}
in other file use it like this.
const isValidUser = validateUserForSubscription(req.body);

Find object by match property in nested array

I'm not seeing a way to find objects when my condition would involve a nested array.
var modules = [{
name: 'Module1',
submodules: [{
name: 'Submodule1',
id: 1
}, {
name: 'Submodule2',
id: 2
}
]
}, {
name: 'Module2',
submodules: [{
name: 'Submodule1',
id: 3
}, {
name: 'Submodule2',
id: 4
}
]
}
];
This won't work because submodules is an array, not an object. Is there any shorthand that would make this work? I'm trying to avoid iterating the array manually.
_.where(modules, {submodules:{id:3}});
Lodash allows you to filter in nested data (including arrays) like this:
_.filter(modules, { submodules: [ { id: 2 } ]});
Here's what I came up with:
_.find(modules, _.flow(
_.property('submodules'),
_.partialRight(_.some, { id: 2 })
));
// → { name: 'Module1', ... }
Using flow(), you can construct a callback function that does what you need. When call, the data flows through each function. The first thing you want is the submodules property, and you can get that using the property() function.
The the submodules array is then fed into some(), which returns true if it contains the submodule you're after, in this case, ID 2.
Replace find() with filter() if you're looking for multiple modules, and not just the first one found.
I think your best chance is using a function, for obtaining the module.
_.select(modules, function (module) {
return _.any(module.submodules, function (submodule) {
return _.where(submodule, {id:3});
});
});
try this for getting the submodule
.where(.pluck(modules, "submodules"), {submodules:{id:3}});
I looked into this and I think the best option is to use Deepdash. It's a collection of methods to do deeply filter, find etc.
Sure it would be possible with lodash alone but with Deepdash it's easier.
I tried to convert the previous answer to the latest Lodash version but that was not working. Every method was deprecated in v4 of Lodash. Possible replacements: select = map or filter, any = some, where = filter)
findDeep returns an object with some information to the found item (just some values, see the docs for more details):
value is the object found
key that's the index in the nested array
parent the parent of the value
So the code for the findDeep looks like:
const modules = [{
name: 'Module1',
submodules: [{
name: 'Submodule1',
id: 1
}, {
name: 'Submodule2',
id: 2
}]
}, {
name: 'Module2',
submodules: [{
name: 'Submodule1',
id: 3
}, {
name: 'Submodule2',
id: 4
}]
}];
const getModule = (modules, id) =>
_.findDeep(modules, module => module.id === id, {
childrenPath: "submodules"
});
const resultEl = document.getElementById("result");
const foundModule = getModule(modules, 3).value;
resultEl.innerText = JSON.stringify(foundModule, null, 2);
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script>
deepdash(_);
</script>
<h2>Example to get module with id = 3</h2>
<pre id="result"></pre>