Just trying to get a handle on Yup and unfortunately I can't seem to find any examples that point to validating a nested object and a nested array (of objects) within another object.
I have something like this:
"books": [{
"info": {
"dateReleased": null,
"timeReleased": null
},
"reviewers": [
{
"company": "",
"name": ""
}
]
}]
I just have no idea what the required Yup validation syntacx is for info and reviewers as all I want to validate is that the values are not null and are required.
I'vetried this but no validation is firing:
Yup.object().shape({
books: Yup.array(
info: Yup.object({
dateReleased: Yup.date().required('Rquired')
timeReleased: Yup.date().required('Required')
})
reviewers: Yup.array(
Yup.object({
company: Yup.string().required('Required')
name: Yup.string().required('Required')
})
)
)
})
With the above, I'm not getting any console errors but none of my validation rules for info and reviewers are firing.
Yup Validation
const value = {
books: [
{
info: {
dateReleased: null,
timeReleased: null,
},
reviewers: [
{
company: "",
name: "",
},
],
},
],
};
const schema = yup.object().shape({
books: yup.array(
yup.object().shape({
info: yup.object().shape({
dateReleased: yup.date().required('Required'),
timeReleased: yup.date().required('Required')
}),
reviewer: yup.array(
yup.object().shape({
company: yup.string().required('Required'),
name: yup.string().required('Required')
})
)
})
),
});
schema.validate(value).catch(err => {
console.log(err.name); // ValidationError
console.log(err.errors); // [books[0].info.timeReleased must be a `date` type, but the final value was: `Invalid Date`.]
});
Related
I am new to GraphQL not sure what I am doing wrong. Any help will be appreciated. I have included my GraphQL schema, data and query here. I am getting exception in query "Value to set in Organization.relationships in not normalizable: Value to set in Relationships.customers in not normalizable: should be an object or null or undefined".
My Schema:
type Query{
searchForOrganization: [Organization!]!
}
type Data{
id: ID
type: String
}
type Group{
data:[Data]
}
type User{
data:[Data]
}
type Customer{
data:[Data]
}
type Relationships{
groups: Group
users: User
customers: Customer
}
type Attributes{
name: String!
description: String
authenticationUrl: String
}
type Organization{
id: ID!
type: String!
attributes: Attributes!
relationships: Relationships!
}
Mock Data:
const mocks = {
Query: () => ({
searchForOrganization: () => [...new Array(9)],
}),
Organization: () => (
{
type: () => "organization",
id: () =>"Test002",
attributes: ()=>{
return{
authenticationUrl: "XXXX",
description: "Test Company",
"name": "Test Company"
};
},
relationships: () => {
return{
customers: () => {
return{
data: [{type: "customer", id: "Test002_Root_customers"},
{type: "customer", id: "Test003_Root_customers"}
]
};},
groups: () => {
return{
data: [{type: "group", id: "Test003_Root_groups"},
{type: "group", id: "Test002_Root_groups"}]
};},
users: () => {
return{
data: [{type: "user", id: "Test003_Root_users"},
{type: "user", id: "Test002_Root_users"}]
};}
};
}
}
),
};
My Query:
query SearchForOrganization {
searchForOrganization {
id
type
attributes {
name
description
authenticationUrl
}
relationships {
groups {
data {
id
type
}
}
users {
data {
id
type
}
}
customers {
data {
id
type
}
}
}
}
}
My Result:
{
"errors": [
{
"message": "Value to set in Organization.relationships in not normalizable: Value to set in Relationships.customers in not normalizable: should be an object or null or undefined. Received () => {\r\n return{\r\n data: [{type: \"customer\", id: \"Test002_Root_customers\"},\r\n {type: \"customer\", id: \"Test003_Root_customers\"}\r\n ]\r\n };}",
"locations": [
{
"line": 10,
"column": 5
}
],
"path": [
"searchForOrganization",
0,
"relationships"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Value to set in Organization.relationships in not normalizable: Value to set in Relationships.customers in not normalizable: should be an object or null or undefined. Received () => {\r",
" return{\r",
" data: [{type: \"customer\", id: \"Test002_Root_customers\"},\r",
" {type: \"customer\", id: \"Test003_Root_customers\"}\r",
" ]\r",
" };}",
Change in schema solved the issue
type TypeAndID{
id: ID
type: String
}
type DataGroup{
data:[TypeAndID]
}
type OrgRelationships{
groups: DataGroup
users: DataGroup
customers: DataGroup
}
type Attributes{
name: String!
description: String
authenticationUrl: String
}
type Organization{
id: ID!
type: String!
attributes: Attributes!
relationships: OrgRelationships!
}
type Data{
data: [Organization!]!
}
type Query{
getOrganizations: Data
}
I have a Gatsby application pulling data from Sanity.
This is Sanity's schema for the course.js:
import video from './video'
export default {
// Computer name
name: `courses`,
// Visible title
title: `Courses`,
type: `document`,
fields: [
{
name: `title`,
title: `Course title`,
type: `string`,
description: `Name of the course`
},
{
name: `slug`,
title: `slug`,
type: `slug`,
options: {
source: `title`,
maxLength: 100,
}
},
{
name: `price`,
title: `Price`,
type: `number`
},
{
name: `thumbnail`,
title: `Thumbnail`,
type: `image`,
options: {
hotspot: true,
}
},
{
name: `playlist`,
title: `Playlist`,
type: `array`,
of: [
{
title: `Video`,
name: `video`,
type: `video`,
}
]
},
]
}
And this is Sanity's schema for video.js:
export default {
// Computer name
name: `video`,
// Visible title
title: `Video`,
type: `object`,
fields: [
{ name: `title`, type: `string`, title: `Video title` },
{ name: `url`, type: `url`, title: `URL` },
{ name: `public`, title: `public`, type: `boolean`, initialValue: false }
]
}
This Gatsby page query:
{
allSanityCourses {
nodes {
title
price
playlist {
url
title
public
}
}
}
}
Results in:
{
"data": {
"allSanityCourses": {
"nodes": [
{
"title": "Master VS Code",
"price": 149,
"playlist": [
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Introduction",
"public": true
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Philosophy",
"public": false
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Tech and Tools",
"public": false
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Integration",
"public": true
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Extensions",
"public": false
}
]
}
]
}
},
"extensions": {}
}
To prevent the url field from being injected into the React component this Gatsby page query runs on (because these urls are paid for), I need to remove it, if the public field is set to false.
I've tried inserting this into gastby-node.js:
exports.createSchemaCustomization = ({ actions, schema }) => {
const { createTypes } = actions
const typeDefs = [
schema.buildObjectType({
name: "SanityCourses",
fields: {
playlist: {
type: "[SanityVideo]",
url: {
type: "String",
resolve: (source) => "nope"
},
},
},
interfaces: ["Node"],
}),
]
createTypes(typeDefs)
}
And:
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
SanityCourses: {
playlist: {
type: "[SanityVideo]",
url: {
type: "String",
resolve(source, args, context, info) {
return "nope"
},
}
},
},
}
createResolvers(resolvers)
}
But neither seems to work. The url field returns the url as always. The resolvers don't even seem to fire (I've tried putting console.log()'s in them).
Any help on how to remove the url field if the public field is set to false, or general direction to go in would be very appreciated.
Ditch the attempt in createSchemaCustomization since you don't need to customize the schema here (though I believe there is a way to achieve what you want using it, it is not expected that the data in it is sourced from existing nodes, and this undeclared dependency can create caching issues).
Then update your createResolvers function to something like this:
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
SanityVideo: {
safeUrl: {
type: "String",
resolve: (source, args, context, info) => source.public ? source.url : null
},
},
})
}
I don't believe resolvers can replace schema-originated nodes (fields), hence using safeUrl instead of url
The type you are adding a field to is SanityVideo, and it doesn't matter what the parent node is—this will apply to all instances of SanityVideo in your data
I have a data structure like this:
{
"subject": "Ah yeah",
"description": "Jeg siger...",
"daysOfWeek": [
{
"dayOfWeek": "MONDAY",
"checked": false
},
{
"dayOfWeek": "TUESDAY",
"checked": false
},
{
"dayOfWeek": "WEDNESDAY",
"checked": true
},
{
"dayOfWeek": "THURSDAY",
"checked": false
},
{
"dayOfWeek": "FRIDAY",
"checked": false
},
{
"dayOfWeek": "SATURDAY",
"checked": true
},
{
"dayOfWeek": "SUNDAY",
"checked": true
}
],
"uuid": "da8f56a2-625f-400d-800d-c975bead0cff",
"taskSchedules": [],
"isInitial": false,
"hasChanged": false
}
In daysOfWeek I want to ensure that at least one of the items has checked: true.
This is my validation schema so far (but not working):
const taskValidationSchema = Yup.object().shape({
subject: Yup.string().required('Required'),
description: Yup.string(),
daysOfWeek: Yup.array()
.of(
Yup.object().shape({
dayOfWeek: Yup.string(),
checked: Yup.boolean(),
})
)
.required('Required'),
taskSchedules: Yup.array(),
})
Is it possible to validate the values of daysOfWeek ensuring that at least one of them has checked: true?
I solved it using compact() (filtering out falsely values) together with setTimeout after the FieldArray modifier function:
const validationSchema = Yup.object().shape({
subject: Yup.string().required(i18n.t('required-field')),
description: Yup.string(),
daysOfWeek: Yup.array()
.of(
Yup.object().shape({
dayOfWeek: Yup.string(),
checked: Yup.boolean(),
})
)
.compact((v) => !v.checked)
.required(i18n.t('required-field')),
taskSchedules: Yup.array(),
});
And in form:
<Checkbox
value={day.dayOfWeek}
checked={day.checked}
onChange={(e) => {
replace(idx, { ...day, checked: !day.checked });
setTimeout(() => {
validateForm();
});
}}
/>;
Base on #olefrank's answer. This code work with me.
const validationSchema = Yup.object().shape({
subject: Yup.string().required(i18n.t('required-field')),
description: Yup.string(),
daysOfWeek: Yup.array()
.of(
Yup.object().shape({
dayOfWeek: Yup.string(),
checked: Yup.boolean(),
})
)
.compact((v) => !v.checked)
.min(1, i18n.t('required-field')), // <– `.min(1)` instead of `.required()`
taskSchedules: Yup.array(),
});
I have done this type of validation in my Node.js(Express.js) project. You can try validation in this way.
const validationSchema = yup.object({
subject: yup.string().required(),
description: yup.string().required(),
daysOfWeek: yup.array(
yup.object({
dayOfWeek: yup.string().required(),
checked: yup.boolean().required()
})
)
})
If you trying in latest version it should be used like this
Yup.array().min(1, "At least one option is required").required()
In my case I have used formik with yup for this,
I want to select only one value in an array if not selected I need to display the error
array = [{"label": "Option 1", "selected": false, "value": "option-1"}, {"label": "Option 2", "selected": false, "value": "option-2"}, {"label": "Option 3", "selected": false, "value": "option-3"}]
Yup.mixed().test({
message: 'Required',test:
val => val.filter(i => i.selected === true).length === 1})
it worked for me
Yup.mixed().test({
message: 'Required',test:
val => val.filter(i => i.selected === true).length !== 0})
With GraphQL, I like to query an entire array with all the fields that are found in only some of the array elements.
Assume I have the following data and local client:
// data1.json
[
{
"type": "title",
"description": "Title!"
},
{
"type": "person",
"description": "He has been working in this office for 10 years."
"name": "Thomas"
"age": "35"
},
{
"type": "office",
"description": "Engineering"
"size": "90"
"budget": "1500000"
},
]
import data1 from './data1.json'
import data2 from './data2.json' // same structure to data1
... // other imports
const client = new ApolloClient({
cache: new InMemoryCache()
});
client.cache.writeData({
data: {
departments: [
{
name: 'departmentOne',
data: data1.map(item => ({ ...item, __typename: 'element' })),
__typename: 'department'
},
{
name: 'departmentTwo',
data: data2.map(item => ({ ...item, __typename: 'element' })),
__typename: 'department'
}
],
__typename: 'departments'
}
});
Then, in one of my component, how do I get all the elements in the departments?
When I query this it just works:
{
departments #client {
name
data {
type
description
__typename
}
__typename
}
}
But the following query will return nothing:
{
departments #client {
name
data {
type
description
name
age
size
budget
__typename
}
__typename
}
}
I suppose I need to add a local resolver or typeDefs for this purpose, but how would it look like?
In the first place, I am not sure if the cache has all the array. As some of the fields (i.e., "name", "age", and others) are missing in some element, might it omit the data automatically?
I'm starting with Apollo GraphQL (Using Axios), and i'm facing a problem when an external API send an ARRAY.
I can't get the variables inside the objects.
I've already tried in several ways, and can't find help anywhere.
const axios = require ('axios');
const {GraphQLObjectType, GraphQLSchema, GraphQLInt,
GraphQLList, GraphQLString } = require('graphql');
const FeedingType = new GraphQLObjectType({
name: 'Feeding',
fields: () => ({
sentry_objects : {type : new GraphQLList(SentryType)},
})
})
//Sentry Objects
const SentryType = new GraphQLObjectType({
name: 'Sentry',
fields: () => ({
designation : {type : GraphQLString},
})
})
//Root Query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
sentry: {
type: new GraphQLList(SentryType),
resolve(parent, args){
return axios
.get('https://api.nasa.gov/neo/rest/v1/neo/sentry?is_active=true&page=0&size=50&api_key=DEMO_KEY')
.then(res => res.data);
}
},
And that's the JSON from API:
{
"links": {
"next": "https://api.nasa.gov/neo/rest/v1/neo/sentry?is_active=true&page=1&size=50&api_key=DEMO_KEY",
"self": "https://api.nasa.gov/neo/rest/v1/neo/sentry?is_active=true&page=0&size=50&api_key=DEMO_KEY"
},
"page": {
"size": 50,
"total_elements": 908,
"total_pages": 19,
"number": 0
},
"sentry_objects": [
{
"links": {
"near_earth_object_parent": "https://api.nasa.gov/neo/rest/v1/neo/3012393?api_key=DEMO_KEY",
"self": "https://api.nasa.gov/neo/rest/v1/neo/sentry/3012393?api_key=DEMO_KEY"
},
"spkId": "3012393",
"designation": "1979 XB",
"sentryId": "bJ79X00B",
"fullname": "(1979 XB)",
"year_range_min": "2056",
"year_range_max": "2113",
"potential_impacts": "2",
"impact_probability": "7.36e-07",
"v_infinity": "23.9194972826087",
"absolute_magnitude": "18.53",
"estimated_diameter": "0.662",
"palermo_scale_ave": "-2.82",
"Palermo_scale_max": "-3.12",
"torino_scale": "0",
"last_obs": "1979-Dec-15.42951",
"last_obs_jd": "2444222.92951",
"url_nasa_details": "https://cneos.jpl.nasa.gov/sentry/details.html#?des=1979+XB",
"url_orbital_elements": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=3012393;orb=1",
"is_active_sentry_object": true,
"average_lunar_distance": 14.2337865829
},
}
Trying to get that "sentry_objects" variables, testing with "designation", but i'm just getting errors like:
{
"errors": [
{
"message": "Expected Iterable, but did not find one for field RootQueryType.sentry.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"sentry"
]
}
],
"data": {
"sentry": null
}
}
Thank you for reading :)
In your RootQuery resolver you are only returning from the promise res.data object, but you should return the res.data.sentry_object object.
Something like:
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
sentry: {
type: new GraphQLList(SentryType),
resolve(parent, args) {
return axios
.get('https://api.nasa.gov/neo/rest/v1/neo/sentry?is_active=true&page=0&size=50&api_key=DEMO_KEY')
.then(res => {
// HERE: return the sentry_objects
console.log(res.data.sentry_objects)
return res.data.sentry_objects
});
}
},
}
})