I'm trying to validate a GET request on Nest.js that has multiple queries using Joi. I understand how to use UsePipes and validate a single object on a single param. However I now have an endpoint that has the multiple queries, here is my controller:
#Get(':cpId/search')
#UsePipes(new JoiValidationPipe(queryDTOSchema))
async getSomethingByFilters(
#Param('cpId') cpId: string,
#Query('startDate') startDate?: number,
#Query('endDate') endDate?: number,
#Query('el') el?: string,
#Query('fields') fields?: string,
#Query('keyword') keyword?: string,
#Query('page') page?: number,
#Query('limit') limit?: number,
)...
And UsePipes is now validating the same schema against each of the queries, and I don't understand how to validate each single query separately.
Is there a way to validate each query separately? I couldn't find any references and the only solution I can think of would be to transform all those queries into a single object, which is undesirable in this case.
You can pass a pipe as the second argument of a query-decorator:
#Query('startDate', new JoiValidationPipe(joi.number())) startDate?: number
But I personally would prefer validation as one query object, as it is easier to read and handle:
#Get(':corporatePartnerId/search')
async getEmployeesByFilters(
#Param('corporatePartnerId', new JoiValidationPipe(joi.string())) corporatePartnerId: string,
#Query(new JoiValidationPipe(QueryDtoSchema)) query: QueryDto,
)
Related
I want to validate an object in mongoose schema, i.e here is my schema -
logs = new Schema({
user_id: String,
reminder_cat: String,
activityNote: String,
sent_email: Number,
added_date: Date
})
I want to validate if reminder_cat === "Renewal" then sent_email should not be more than 2 how do I achieve this at schema level. I understand there are validate function at attribute level which can be custom or provided from mongoose. But that doesn't contain the whole object so validating a dependent field is not possible. Any help or pointer will be appreciated.
I am using graphQL, sequelize and nodejs with apollo client.
The data which I am sending from the UI is a nested structure of the following form:
Grandparent
Parent
Child
So a grandparent can have one or more parents and a parent can have one or more children.
I am trying to update my SQLite database, created using sequelize, using one GraphQL mutation. I am able to create a mutation with a flat structure:
schema.gql file contents ->
type Mutation Family(
grandParentName: String,
grandParentHeight: String,
Parent: String,
)
but I want something along the lines of
type Mutation CreateNestedFamily(
grandParentName: String,
grandParentHeight: String,
Parent: CreateParent(
parentName: String,
parentHeight: String
child: CreateChild(
childName: String,
childHeight: String
)
)
)
But I dont know how to achieve this and the graphql documentation around nested mutations is very limited.
Any help would be appreciated!
The way you've phrased you problem is a little strange, but i'll do my best to point you in the right direction.
There's no such thing as a nested mutation in GraphQL, but you can construct input types that allows an arbitrary nesting of data that you pass to a single mutation.
I'll step back from your approach and take a specific problem "I want to create a person and their descendants"
input PersonInput {
name: String!
height: String!
children: [PersonInput!]
}
type Mutation {
createPerson(person: PersonInput!): SomeOutputType
}
Hopefully you can see the recursive nature of this structure. It'd be more difficult to impose a limit on this, i.e to only allow 3 levels deep.
Is it possible to leverage both GraphQL and Mongoose?
So far, I have been able to integrate both GraphQL and Mongoose to handle populating the database, but I am struggling to understand how this can work to retrieve data, specifically data with nested references.
Consider this schema:
const fooSchema = new Schema({
name: { type: 'String', required: true },
bar: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Bar',
required: false,
}],
});
The Bar schema is essentially the same, with just a field for "name".
Is it possible to run a GraphQL query to populate the data with the references in 'bar'?
Currently, we are using GraphQL-Tools to create our typeDefs, Mutations, and Queries which looks something like this:
const typeDefs = `
type Foo {
name: String!,
bars:[Bar]
}
type Bar {
_id: ID,
name: String,
}
type Query {
allFoos: [Foo!]!
foo(_id: ID!): Foo
}
type Mutation {
...
}
`;
module.exports = makeExecutableSchema({typeDefs, resolvers});
And finally a query directive that looks like this:
const allFoos = async (root, data) => {
return await Foo.find({});
};
I am able to change the query directive to use .populate() to get Bar, but that does not actually end up populating the results, which I think is because of the way the typeDefs are set up.
So is it possible to make these two concepts work together? Does it even make sense to use them both?
As they describe GraphQL:
GraphQL is a query language for your API, and a server-side runtime
for executing queries by using a type system you define for your data.
GraphQL isn't tied to any specific database or storage engine and is
instead backed by your existing code and data.
Where as mongoose is
Writing MongoDB validation, casting and business logic boilerplate is
a drag. That's why we wrote Mongoose
Monogoose work with mongodb validation whereas graphql is a query language for the API.
You can read a basic example from here about Setting up a simple GraphQL Server with Node, Express and Mongoose.
These two are completely different. Mongoose work when you are performing any operation on database, whereas grapgl comes in picture when you call a API. Graphql validate your API input parameter and return parameter. If you are adding these two in single app. It will work well.
Mongoose will validate your db operation.
GraphQL will validate your API input and output parameter.
I'm using Sequelize with Postgres and Angular.js in the front-end.
I'm setting up some routes to expect arrays in the response:
'getData': {
method: 'GET',
// isArray: true,
url: 'stuff/:id',
params: {id: '#id'}
}
However, when only one record is retrieved Sequelize seems to return an object directly
rather than an array with one object in it, which breaks the resource:
Error in resource configuration. Expected response to contain an array but got an object
Is there a way of setting up Sequelize to always return arrays even if there's only one record retrieved?
Or, a clean way of wrapping the data when it gets to ng-resource?
Thanks!
Angular should support object responses, but in any case:
Model.find() will return an object, Model.findAll() will return an array. You can just swap to using a findAll, if filtering on primary key it won't make much of a difference.
Model.find() also takes query parameters as it's second parameter so you should also be able to do Model.find({where: ..}, {plain: false}) but that hasn't been tested and isn't exactly public API.
Is it considered bad practice to use associative arrays in mongodb? I'm curious as to why mongoose doesn't seem to provide this in its Schema definition.
If by "associative array", you mean "Object", that works fine. You can use just regular old "Object" or you can specify specific properties or you can use "mongoose.Schema.Types.Mixed" to allow varying types.
{
//regular old javascript/json data types
created: Date,
//this works just fine
statistics: Object,
//or you can specify the shape of the object
address: {state: String, line1: String},
//for the extra features you get with a true subdocument
nested: [SomeOtherMongooseSchema],
//Could be array, boolean, number, whatever. Can vary with each document.
grabBag: mongoose.Schema.Types.Mixed
}
Considering you use mongoose version > 5.1.0
As specified here in the documentation: https://mongoosejs.com/docs/schematypes.html#maps
You can use Map this way to specify an associative array :
myAssociativeArray: {
type: Map,
of: String
}
By the way i don't know if you can specify the key type with this syntax