Hi I am wondering if I can make a validation that is not based on a user input but based on an object derived from somewhere else. For example I have an object like this:
userDetails{
"id":1,
"surname":"Wood",
"firstName":"Victor"
}
and I have a Yup validation like this
export const userDetailValidation= Yup.object().shape({
surname: Yup.string().
.required("This field is required.")
.max(50, "Maximum character is 50.")
firstName: Yup.string().
.required("This field is required.")
.max(50, "Maximum character is 50.")
});
What can I do so that I can validate the object that I have based on that Yup Validation?
Yes, you can use the Yup validation to validate your object. You can use the .validate() method to check if the object meets the validation requirements. For example:
const isValid = userDetailValidation.validate(userDetails, {abortEarly: false});
If the validation passes, isValid will be true. Otherwise, it will be false.
Related
React v16, formik, yup.
I am building a form in which a user must first select their state. this is a select field.
There is a second field for license, which will require different validation based on the state. I have a list of regex values that work fine if i add one directly to Yup. for exmaple:
export const form = Yup.object().shape({
state: Yup.string().required(),
license: Yup.string()
.when("required", {
is: (required) => required === true,
then: Yup.string()
.required("This field is required")
.matches(/^[0-9]{14}$/, "Please enter the ID in the proper format"),
}),
the above code, hardcoded regex, works great.
the question is how can i return a regex value in place of /^[0-9]{14}$/, from an array i have with all the regex values? when a user picks a state i want that regex to be switched out for their license.
I've tried adding functions (staying away from using arrow functions globally in the Yup validation schema due to issues with binding to this per their docs at Yup
another thing i've tried is adding a field in my form called "regex". this gets set when the user picks their state in the form. its an invisible field i set with Formik.setFieldValue which retains the regex, which i can call from the validation. doesn't work
license: Yup.string()
.when(["required", regex], {
is: (required) => required === true,
then: (regex) => Yup.string()
.required("This field is required")
.matches(regex, "Please enter the ID in the proper format"),
even when i try and create a new regexp w js, no luck
.matches(new RegExp(/^[0-9]{14}$/), "Please enter the ID in the proper format"),
it seems like i can get this work 1 time, but on state changes, the value on formik never gets re-evaluated.
to reiterate my question:
How can i add dynamic regex for one field in Yup, based on a second field?
I use react-hook-forms with typescript and react native. When I set the defaultValues field in the useForm method I need to have in the beginning empty fields, there is no problem when the field is a string, but I have fields that for example should be a date. When I set the date to undefined I get a warning - fieldname is missing in the 'defaultValue' prop of either its controller or useForm, and when I try to set it to null I get some TypeScript error that the field in defaultValues must be either a Date or undefined, since react-hook-forms DefaultValues type can accept each field as an actual value or undefined.
So basically for each solution I get an error / warning. How can I solve that?
Thanks ahead.
EDIT:
The form data type:
interface FormData {
date: Date;
}
But - the DefaultValue type for this form (this is from react-hook-form) is:
{
date: Date | undefined;
}
EDIT V2:
I found a solution - in my case I used the Controller component defaultValue prop with null and it worked.
I want to create an Input type which takes some inputs (from authenticated as well as non-authenticated users). I want to be able to restrict some input fields based on the authentication.
But I am aware that there is no resolve method for input types. So how do I achieve this?
Input UserInput {
data: String!
shareWith: [ID!] #auth(requires: USER)
}
Can someone please help me if it is possible to make a directive which can work with input types?
Reaching to you all as I am in the learning process and integration of Apollo and graphQL into one of my projects. So far it goes ok but now I am trying to have some mutations and I am struggling with the Input type and Query type. I feel like it's way more complicated than it should be and therefore I am looking for advice on how I should manage my situation. Examples I found online are always with very basic Schemas but the reality is always more complex as my Schema is quite big and look as follow (I'll copy just a part):
type Calculation {
_id: String!
userId: String!
data: CalculationData
lastUpdated: Int
name: String
}
type CalculationData {
Loads: [Load]
validated: Boolean
x: Float
y: Float
z: Float
Inputs: [Input]
metric: Boolean
}
Then Inputs and Loads are defined, and so on...
For this I want a mutation to save the "Calculation", so in the same file I have this:
type Mutation {
saveCalculation(data: CalculationData!, name: String!): Calculation
}
My resolver is as follow:
export default resolvers = {
Mutation: {
saveCalculation(obj, args, context) {
if(context.user && context.user._id){
const calculationId = Calculations.insert({
userId: context.user._id,
data: args.data,
name: args.name
})
return Calculations.findOne({ _id: calculationId})
}
throw new Error('Need an account to save a calculation')
}
}
}
Then my mutation is the following :
import gql from 'graphql-tag';
export const SAVE_CALCULATION = gql`
mutation saveCalculation($data: CalculationData!, $name: String!){
saveCalculation(data: $data, name: $name){
_id
}
}
`
Finally I am using the Mutation component to try to save the data:
<Mutation mutation={SAVE_CALCULATION}>
{(saveCalculation, { data }) => (
<div onClick={() => saveCalculation({ variables : { data: this.state, name:'name calcul' }})}>SAVE</div>
}}
</Mutation>
Now I get the following error :
[GraphQL error]: Message: The type of Mutation.saveCalculation(data:)
must be Input Type but got: CalculationData!., Location: undefined,
Path: undefined
From my research and some other SO posts, I get that I should define Input type in addition to the Query type but Input type can only avec Scalar types but my schema depends on other schemas (and that is not scalar). Can I create Input types depending on other Input types and so on when the last one has only scalar types? I am kinda lost cause it seems like a lot of redundancy. Would very much appreciate some guidance on the best practice. I am convinced Apollo/graphql could bring me quite good help over time on my project but I have to admit it is more complicated than I thought to implement it when the Schemas are a bit complex. Online examples generally stick to a String and a Boolean.
From the spec:
Fields may accept arguments to configure their behavior. These inputs are often scalars or enums, but they sometimes need to represent more complex values.
A GraphQL Input Object defines a set of input fields; the input fields are either scalars, enums, or other input objects. This allows arguments to accept arbitrarily complex structs.
In other words, you can't use regular GraphQLObjectTypes as the type for an GraphQLInputObjectType field -- you must use another GraphQLInputObjectType.
When you write out your schema using SDL, it may seem redundant to have to create a Load type and a LoadInput input, especially if they have the same fields. However, under the hood, the types and inputs you define are turned into very different classes of object, each with different properties and methods. There is functionality that is specific to a GraphQLObjectType (like accepting arguments) that doesn't exist on an GraphQLInputObjectType -- and vice versa.
Trying to use in place of another is kind of like trying to put a square peg in a round hole. "I don't know why I need a circle. I have a square. They both have a diameter. Why do I need both?"
Outside of that, there's a good practical reason to keep types and inputs separate. That's because in plenty of scenarios, you will expose plenty of fields on the type that you won't expose on the input.
For example, your type might include derived fields that are actually a combination of the underlying data. Or it might include fields to relationships with other data (like a friends field on a User). In both these case, it wouldn't make sense to make these fields part of the data that's submitted as as argument for some field. Likewise, you might have some input field that you wouldn't want to expose on its type counterpart (a password field comes to mind).
Yes, you can:
The fields on an input object type can themselves refer to input object types, but you can't mix input and output types in your schema. Input object types also can't have arguments on their fields.
Input types are meant to be defined in addition to normal types. Usually they'll have some differences, eg input won't have an id or createdAt field.
Is there a way to restrict which fields are sent in the response at a model level. Assume I have the following schema:
var mySchema = new.mongoose.Schema({
public_field1: String,
public_field2: String,
private_field1: String,
private_field1: String,
})
Let's say I want to get all those fields back when I do my query because the private fields are used for some processing, but I only want to send the public fields to the final response. What is the best way to handle that without having to specify it every single route function?
You can use the select property on the field definitions in your schema to determine if the field is included by default or not. For example, to exclude the private fields by default:
var mySchema = new.mongoose.Schema({
public_field1: String,
public_field2: String,
private_field1: {type: String, select: false},
private_field2: {type: String, select: false}
})
Then when you do want those fields you can include them in your results via:
MyModel.find().select('+private_field1 +private_field2').exec(callback);