JOI alternatives try - need one to be required - node.js

I'm trying to validate a query string using JOI and express-validation.
I need the query param ?query[primaryOrgId]=5d2f2c836aeed10026ccba11 to be either a single string or an array of strings, and it is required.
The following schema is validating the primaryOrgId as expected when it is present, but it is not validating that it is required:
index: {
body: {},
query: {
query: {
primaryOrgId: Joi.alternatives().try(
Joi.array().items(Joi.string().regex(mongoId)),
Joi.string().regex(mongoId),
).required()
},
},
options: {
allowUnknownQuery: false,
allowUnknownBody: false,
},
},
I've also tried:
index: {
body: {},
query: {
query: {
primaryOrgId: Joi.alternatives().try(
Joi.array().items(Joi.string().regex(mongoId).required()),
Joi.string().regex(mongoId).required(),
)
},
},
options: {
allowUnknownQuery: false,
allowUnknownBody: false,
},
},
}
How can I ensure that primaryOrgId is present in the query string?

I am not 100% sure about your requirements, but here is a Joi ("#hapi/joi": "^17.1.1") schema with a few changes:
const schema = Joi.alternatives().try(
Joi.array().min(1).items(Joi.string().trim()), // length have to be at least 1
Joi.string().trim()
).required(); // required added
// String
console.log(schema.validate(undefined)); // error: [Error [ValidationError]: "value" is required]
console.log(schema.validate('')); // error: [Error [ValidationError]: "value" is not allowed to be empty]
console.log(schema.validate(' ')); // error: [Error [ValidationError]: "value" is not allowed to be empty]
console.log(schema.validate('foo')); // value: 'foo'
// Array
console.log(schema.validate([])); // error: [Error [ValidationError]: "value" must contain at least 1 items]
console.log(schema.validate([' '])); // error: [Error [ValidationError]: "[0]" is not allowed to be empty]
console.log(schema.validate(['foo'])); // value: [ 'foo' ]
console.log(schema.validate(['foo', 'bar'])); // value: [ 'foo', 'bar' ]
Let me know if this works well for you. Otherwise I will update my answer.

Related

request body validation with fastest validator

i want to change the error style of fastest validator.
copy from fastest validator document
const Validator = require("fastest-validator");
const v = new Validator();
const schema = {
id: { type: "number", positive: true, integer: true },
name: { type: "string", min: 3, max: 255 },
status: "boolean" // short-hand def
};
enter code here
const check = v.compile(schema);
console.log("Second:", check({ id: 2, name: "Adam" }));
/* Returns an array with errors:
[
{
type: 'required',
field: 'status',
message: 'The \'status\' field is required!'
}
]
*/
in the top example the error have some key value but i want this syntax :
[
{
status: 'The \'status\`enter code here`' field is required!',
}
]
For this, we need to prepare a response likewise
Use try and catch then so we can grab that error in catch block and we can change the syntax of error accordingly.
try {
// Your code
} catch (error) {
console.log(error) // Look into where this message is located
return res.json([
{
status: error.message
}
])
}

remove document after virtual populating

I am aggregating a collection. Then virtually populating that document but some of the virtual documents have banned: true so i want to remove that documents.
This is the code:
const populatedManager = await Report.populate(reportedManagers, {
path: "managerId",
options: { select: { name: 1, avatar: 1 }, lean: true },
match: { banned: false },
});
Now i have to remove that all those documents which have managerId: null because match: { banned: false }.
I have tried to make populatedManager a POJO by chaining this method to populate lean() or this execPopulate().then((populatedManager) => populatedManager.toObject()); but it gives me this error message: "Report.populate(...).execPopulate is not a function".
Another try could be this:
populatedManager.forEach((doc, i) => {
if (doc.managerId === null) delete populatedManager[i];
});
const final = await Report.populate(populatedManager, {
path: "reportTypes.reasonId",
options: {
select: { title: 1 },
},
});
But this gives me error in the below virtual population message: "Cannot read properties of undefined (reading '_doc')"
Please help me to remove the document.

AJV JsonSchema validator reports seemingly incorrect error

I'm using AJV to validate a HTTP request payload against a schema. However, I see an error reported that I was not expecting. This is a code example to demonstrate the issue:
const schema = {
type: 'array',
minItems: 1,
items: {
anyOf: [
{
type: 'object',
properties: {
op: {
enum: ['replace']
},
path: {
type: 'string',
pattern: '/data/to/foo/bar',
},
value: {
type: 'string',
},
},
},{
type: 'object',
properties: {
op: {
enum: ['replace']
},
path: {
type: 'string',
pattern: '/data/to/baz',
},
value: {
type: 'object',
required: ['foo', 'bar'],
properties: {
foo: {
type: 'string',
},
bar: {
type: 'string',
},
}
}
}
}
],
},
}
const validator = new ajv()
const compiledValidator = validator.compile(schema)
const data = [
{ // this object should pass
op: 'replace',
path: '/data/to/foo/bar',
value: 'foo',
},
{ // this object should fail in the `value` mismatch (missing required attribute)
op: 'replace',
path: '/data/to/baz',
value: {
foo: 'bar',
},
},
]
compiledValidator(data)
console.log(compiledValidator.errors)
The schema defines a number of objects to which an incoming list of data objects should match. The first data item matches the schema (first item schema), however the second data item misses a required attribute (bar) in the value object.
When I run the above code I get the following output:
[
{
instancePath: '/1/path',
schemaPath: '#/items/anyOf/0/properties/path/pattern',
keyword: 'pattern',
params: { pattern: '/data/to/foo/bar' },
message: 'must match pattern "/data/to/foo/bar"'
},
{
instancePath: '/1/value',
schemaPath: '#/items/anyOf/1/properties/value/required',
keyword: 'required',
params: { missingProperty: 'bar' },
message: "must have required property 'bar'"
},
{
instancePath: '/1',
schemaPath: '#/items/anyOf',
keyword: 'anyOf',
params: {},
message: 'must match a schema in anyOf'
}
]
I understand the 2nd and the 3rd (last) errors. However, The first error seems to indicate that the path doesn't match path requirements of the first item schema. It is true that the 2nd data item doesn't match the 1st schema item but I don't seem to understand how it is relevant. I would assume that the error would be focused around the value, not the path since it matches on the path schemas.
Is there a way to get the error reporting more focused around the errors that matter?
There is no way for the evaluator to know whether you intended the first "anyOf" subschema to match or the second, so the most useful thing to do is to show you all the errors.
It can be confusing because you don't need to resolve all the errors, just some of them, which is why some implementations also offer a heirarchical error format to make it more easy to see relationships like this. Maybe if you request that ajv implement more of these error formats, it will happen :)
You can see that all of the errors pertain to the second item in the data by looking at the instancePath for each error, which all start with /1. This is the location within the data that generated the error.
So let's look at the second item and compare it against the schema.
{ // this object should fail in the `value` mismatch (missing required attribute)
op: 'replace',
path: '/data/to/baz',
value: {
foo: 'bar',
},
}
The schema says that an item should either (from the anyOf) have
path: '/data/to/foo/bar' and value: { type: 'string' }, or
path: '/data/to/baz' and value: { required: [ 'foo', 'bar' ] }
The reported errors are:
The first case fails because path is wrong.
The second case fails because /value/bar is not present.
The last error is just the anyOf reporting that none of the options passed.

How to resolve GraphQl mutations that have an array as the input

So am new to GraphQL and I'm trying to resolve a mutation that has an Input type of an array. I'm getting this error
{
"data": {
"createSub": null
},
"errors": [
{
"message": "Variable '$data' expected value of type 'SubCreateInput!' but got: {\"apps\":[{\"name\":\"ma\",\"package\":\"me\",\"running\":true,\"isSysytem\":true}]}. Reason: 'apps' Expected 'AppListCreateManyInput', found not an object. (line 1, column 11):\nmutation ($data: SubCreateInput!) {\n ^",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createSub"
]
}
]
}
This is my schema
type Mutation {
createSub(input:subInput): Sub
}
input subInput{
apps: [AppListInput]
}
type Sub{
id: ID!
apps: [AppList]
}
type AppList {
id: ID!
name: String
package: String
running: Boolean
isSysytem: Boolean
}
input AppListInput {
name: String
package: String
running: Boolean
isSysytem: Boolean
}
And this is my resolver
function createSub(root, args, context) {
return context.prisma.createSub({
apps: args.input.apps
})
}
The mutation/payload am sending on the Graphql playground is this
mutation{
createSub( input:{
apps: [{
name: "ma"
package: "me"
running: true
isSysytem: true
}],
})
{
apps{
name
}
}
}
When I console.log(args.input.apps) I'm getting this
[ [Object: null prototype] { name: 'ma', package: 'me', running: true, isSysytem: true } ]
This is the input AppListCreateManyInput generated in the schema
input AppListCreateManyInput {
create: [AppListCreateInput!]
connect: [AppListWhereUniqueInput!]
}
What could I be missing please?
You need to provide the appropriate object to createSub, as shown here. Because apps is a relation, you can't just pass an array of apps in -- after all, when creating the Sub, you may want to either create new apps and relate them to the newly created Sub, or simply relate existing apps to it.
return context.prisma.createSub({
apps: {
create: args.input.apps, // create takes an array of apps to create
}
})
If you wanted to connect existing apps instead of creating new ones, you would use connect instead of create and pass in an object specifying a where condition instead of an array.

Failed to parse: filter: mongoDB error

I am trying to query the data from a collection with a date range field , my document has regex search implemented,
my query is as follows,
db.getCollection('_event').find([{"name":{"$regex":"2017","$options":"i"}},{},{"date.start:{$gte":"2017-03-07T18:30:00.000Z"},{"date.end:{$lt":"2017-11-16T18:30:00.000Z"}])
and mongo throws an error
Error: error: { "waitedMS" : NumberLong(0), "ok" : 0, "errmsg" :
"Failed to parse: filter: [ { name: { $regex: \"2017\", $options:
\"i\" } }, {}, { date.start:{$gte: \"2017-03-07T18:30:00.000Z\" }, {
date.end:{$lt: \"2017-11-16T18:30:00.000Z\" } ]. 'filter' field must
be of BSON type Object.", "code" : 9 }
any help guys?
The argument to the find method must be a JSON/BSON document, not a list. Try
db.getCollection('_event').find({
"name":{"$regex":"2017","$options":"i"},
"date.start":{"$gte":"2017-03-07T18:30:00.000Z"},
"date.end":{"$lt":"2017-11-16T18:30:00.000Z"}
})

Resources