How to validate array of objects in laravel? - laravel

I have an array of objects with different, dynamic parameters. And I'm trying to find a way to validate it based on the object type value.
Is there any way to make it with the FormRequest?
[
{
type: “link”,
url: “https://link.com”,
...
},
{
type: “image”,
id: “drre-ggre-765”,
image: “url”
...
}
]

Related

Is there a way make the fields of a GraphQLObjectType dynamic/non-required inorder to recive a dynamic key value pair

I am trying the GraphQL for the first time. I have a express-graphql server connected to MySQL for hypothetical juice shops, where a owner has ability add or remove or rename the serve type.
For example
Shop A has serves like "Cute Small","The Regular" and "Extravaganza"
Where as shop B serves like "Xsmall","small","medium","large" and "Xlarge"
As the GraphQL fields are mandatory, I am unable think of solution for this particular scenario.
In short, I would love to know if there is a way to write a GraphQLObjectType where the fields can be any/not mentioned.
Snippet of a menu type, were the fields is very specific
var typeDef = new GraphQLObjectType({
name: "Menu",
fields: {
name: { type: GraphQLString },
small_serve: { type: GraphQLFloat },
regular_serve: { type: GraphQLFloat },
medium_serve: { type: GraphQLFloat },
large_serve: { type: GraphQLFloat },
},
});
GraphiQL
{
menus{
name,
small_serve,
regular_serve,
medium_serve,
large_serve
}
}

How can you implement "temporary placeholders" in data structures?

I am trying to boil down a pretty complicated problem into its essence so I can get some help on how to model or architect it. Here it goes.
Say we are compiling functions in this order:
function test() {
sum(mul(2, 3), mul(3, 4))
}
function sum(a, b) {
return a + b
}
function mul(a, b) {
return a * b
}
We end up with an AST something like this:
{
type: 'Program',
blocks: [
{
type: 'Function',
name: 'test',
args: [],
body: [
{
type: 'Call',
function: 'sum',
args: [
{
type: 'Call',
function: 'mul',
...
},
...
]
}
]
},
{
type: 'Function',
name: 'mul',
args: ...,
body: ...
},
{
type: 'Function',
name: 'sum',
args: ...,
body: ...
}
]
}
Now we start compiling this AST into more easily manipulated objects, with direct pointers to functions and such. The final result might look like this:
{
type: 'Program',
blocks: [
{
type: 'Function',
name: 'test',
args: [],
body: [
{
type: 'Call',
pointer: 2,
args: [
{
type: 'Call',
pointer: 1,
...
},
...
]
}
]
},
{
type: 'Function',
name: 'mul',
args: ...,
body: ...
},
{
type: 'Function',
name: 'sum',
args: ...,
body: ...
}
]
}
The main difference is that the "final" version has a pointer to the index where the function is defined. This is a very rough sketch. The reality would be there could be multiple passes required to resolve some context sensitivity, and so you end up with multiple partial/intermediate data structures in the transition from the AST to the final compiled object.
How do you make types to deal with this situation? The ideal is that there is an "initial" and a "final" type. The reality is that on our first pass, we have a "placeholder type" for the function calls, which we can't resolve until we have completed our first pass. So on the first pass, we have:
function: String
On the second pass we change it to:
pointer: Int
How do you reconcile this? How do you architect the algorithm so as to allow for these "placeholder" types for the final data structure?
I have tried searching the web for these sorts of topics but haven't found anything:
partial types
intermediate types
placeholder types
virtual types
temporary types
transitional types
how to have temporary placeholders in data structures
etc.
Create a hashmap.
In a first pass write name/index pairs to the hashmap without modifying the AST itself. For the example that would result in this hashmap (represented in JSON format):
{
"mul": 1,
"sum": 2
}
In a second pass you can use the hashmap to replace references to the keys of this hashmap with a pointer property that gets the corresponding value.
I would suggest not trying to understand how to store intermediate data types, but understanding how to store "references" or "holes". Go look up how a typical serialization/deserialization algorithm works (especially one that can deal with something like repeated substructure or circular references): http://www.dietmar-kuehl.de/mirror/c++-faq/serialization.html
It may give you helpful ideas.

Hapijs Joi reference schema keys to reuse in other models or in routes

I have an example model constructed like so:
const MyModelResponse = Joi.object().keys({
id: Joi.number().integer().required()
.description('ID of the example model'),
description: Joi.string()
.description('Description of the example model'),
})
.description('example instance of MyModel with the unique ID present')
.label('MyModelResponse');
In my route, I want to make sure that my input parameter is validated against the id property of MyModeResponse like so:
validate: {
params: {
id: MyModelResponse.id,
},
options: { presence: 'required' },
failAction: failAction('request'),
}
This results in the schema validation error upon server start:
AssertionError [ERR_ASSERTION]: Invalid schema content: (id)
Is there a way to reference a key of a schema? Currently, I have to resort to either of the following:
Not referencing my MyModelResponse schema at all:
validate: {
params: {
id: Joi.number().integer().description('id of MyModel instance to get'),
},
options: { presence: 'required' },
failAction: failAction('request'),
}
Not using the Joi.object.keys() constructor by defining my model like this:
const MyModelResponse = {
id: Joi.number().integer().required()
.description('ID of the example model'),
description: Joi.string()
.description('Description of the example model'),
}
The bottom approach allows me to reference the id property in my route but doesn't allow me to add descriptions and labels to my schema. I have tried using MyModel.describe().children.id in my route validation and I have made some attempts to deserialize the id object into a schema object to no avail.
Any suggestions would be appreciated.
Remove the keys() and use as follows
const MyModelResponse = Joi.object({
id: Joi.number().integer().required()
.description('ID of the example model'),
description: Joi.string()
.description('Description of the example model'),
})
.description('example instance of MyModel with the unique ID present')
.label('MyModelResponse');

GraphQL: how to have it return a flexible, dynamic array, depending on what the marketeer filled in? [duplicate]

We are in the situation that the response of our GraphQL Query has to return some dynamic properties of an object. In our case we are not able to predefine all possible properties - so it has to be dynamic.
As we think there are two options to solve it.
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
/*
THIS is our special field which needs to return a dynamic object
*/
},
// ...
},
});
As you can see in the example code is element the property which has to return an object. A response when resolve this could be:
{
name: 'some name',
elements: {
an_unkonwn_key: {
some_nested_field: {
some_other: true,
},
},
another_unknown_prop: 'foo',
},
}
1) Return a "Any-Object"
We could just return any object - so GraphQL do not need to know which fields the Object has. When we tell GraphQL that the field is the type GraphQlObjectType it needs to define fields. Because of this it seems not to be possible to tell GraphQL that someone is just an Object.
Fo this we have changed it like this:
elements: {
type: new GraphQLObjectType({ name: 'elements' });
},
2) We could define dynamic field properties because its in an function
When we define fields as an function we could define our object dynamically. But the field function would need some information (in our case information which would be passed to elements) and we would need to access them to build the field object.
Example:
const MyType = new GraphQLObjectType({
name: 'SomeType',
fields: {
name: {
type: GraphQLString,
},
elements: {
type: new GraphQLObjectType({
name: 'elements',
fields: (argsFromElements) => {
// here we can now access keys from "args"
const fields = {};
argsFromElements.keys.forEach((key) => {
// some logic here ..
fields[someGeneratedProperty] = someGeneratedGraphQLType;
});
return fields;
},
}),
args: {
keys: {
type: new GraphQLList(GraphQLString),
},
},
},
// ...
},
});
This could work but the question would be if there is a way to pass the args and/or resolve object to the fields.
Question
So our question is now: Which way would be recommended in our case in GraphQL and is solution 1 or 2 possible ? Maybe there is another solution ?
Edit
Solution 1 would work when using the ScalarType. Example:
type: new GraphQLScalarType({
name: 'elements',
serialize(value) {
return value;
},
}),
I am not sure if this is a recommended way to solve our situation.
Neither option is really viable:
GraphQL is strongly typed. GraphQL.js doesn't support some kind of any field, and all types defined in your schema must have fields defined. If you look in the docs, fields is a required -- if you try to leave it out, you'll hit an error.
Args are used to resolve queries on a per-request basis. There's no way you can pass them back to your schema. You schema is supposed to be static.
As you suggest, it's possible to accomplish what you're trying to do by rolling your own customer Scalar. I think a simpler solution would be to just use JSON -- you can import a custom scalar for it like this one. Then just have your elements field resolve to a JSON object or array containing the dynamic fields. You could also manipulate the JSON object inside the resolver based on arguments if necessary (if you wanted to limit the fields returned to a subset as defined in the args, for example).
Word of warning: The issue with utilizing JSON, or any custom scalar that includes nested data, is that you're limiting the client's flexibility in requesting what it actually needs. It also results in less helpful errors on the client side -- I'd much rather be told that the field I requested doesn't exist or returned null when I make the request than to find out later down the line the JSON blob I got didn't include a field I expected it to.
One more possible solution could be to declare any such dynamic object as a string. And then pass a stringified version of the object as value to that object from your resolver functions. And then eventually you can parse that string to JSON again to make it again an object on the client side.
I'm not sure if its recommended way or not but I tried to make it work with this approach and it did work smoothly, so I'm sharing it here.

GraphQL Root Query: Same schema, different types

I'm pretty new to GraphQL and within my root query I have two fields that are very similar aside from their "type" property, that I would like to combine.
allPosts returns an array of post objects, while post returns a single post.
Each field is using the same schema, and the loaders/resources are being determined within those respective fields based on the argument passed in.
const RootQuery = new graphql.GraphQLObjectType({
name: 'Query',
description: 'Root Query',
fields: {
allPosts: {
type: new graphql.GraphQLList(postType),
args: {
categoryName: {
type: graphql.GraphQLString
}
},
resolve: (root, args) => resolver(args)
},
post: {
type: postType,
args: {
slug: {
type: graphql.GraphQLString
}
},
resolve: (root, args) => resolver(args)
},
});
Is it possible to combine these two fields into one and have the type determined by the argument passed in or another variable?
No, you can't!
Once you define a field as GraphQLList, you always get an array. There is no chance that you suddenly get an object instead of array of.
Same apply to other case when you define field as GraphQLObjectType (or any other scalar type) and you want get an array as result.
Those two fields have really different purposes.
Anyway, you can always add a limit logic to your allPosts field and limit the result to one. But, nevertheless you get always array with only one post

Resources