Mutation with list of strings Variable "$_v0_data" got invalid value Graphql Node.js - node.js

I have this simple mutation that works fine
type Mutation {
addJob(
url: String!
description: String!
position: String!
company: String!
date: DateTime!
tags: [String!]!
): Job
}
Mutation Resolver
function addJob(parent, args, context, info) {
console.log('Tags => ', args.tags)
// const userId = getUserId(context)
return context.db.mutation.createJob(
{
data: {
position: args.position,
componay: args.company,
date: args.date,
url: args.url,
description: args.description,
tags: args.tags
}
},
info
)
}
however, once I tried to put an array of strings(tags) as you see above I I can't get it to work and I got this error
Error: Variable "$_v0_data" got invalid value { ... , tags: ["devops", "aws"] }; Field "0" is not defined by type JobCreatetagsInput at value.tags.
If I assigned an empty array to tags in the mutation there is no problem, however if I put a single string value ["DevOps"] for example i get the error

The issue was in the resolver function apparently as I found here I have to assign the tags list within an object in the set argument like the code below
function addJob(parent, args, context, info) {
return context.db.mutation.createJob(
{
data: {
position: args.position,
componay: args.company,
date: args.date,
url: args.url,
description: args.description,
tags: { set: args.tags }
}
},
info
)
}

Related

Defining a simple union return type in a graphql schema

I’m actually unsure why, but I can’t seem to fix this seemingly simple problem. I have a graphql schema as follows:
import { gql } from 'apollo-server-core';
export const querySchema = gql`
type AffiliateBalance {
pendingBalance: Float!
qualifiedBalance: Float!
}
type Query {
me: User!
users(input: PaginationInput): [User!]!
user(id: Int!): User!
referrals(input: GetReferralsInput): GetReferralsResponse!
affiliateTransactions(
limit: Int
skip: Int
type: TransactionType
): GetAffiliateTransactionsResponse!
affiliatePerformanceMetrics: AffiliatePerformanceMetricsResponse!
affiliateSessions(limit: Int, skip: Int): GetAffiliateSessionsResponse!
affiliateSessionMetrics: AffiliateSessionMetricsResponse!
affiliateBalancePending: Float!
affiliateBalanceQualified: Float!
affiliateBalance: Float! | AffiliateBalance!
}
`;
I have recently added an affiliateBalance query, which can either return a number to 2DP (e.g. 47.28), or this object:


`{ pendingBalance: some2DPNumber, qualifiedBalance: some2DPNumber }`
But I am getting this error:
return new _GraphQLError.GraphQLError(`Syntax Error: ${description}`, {
^
GraphQLError: Syntax Error: Expected Name, found "|"
What am I doing wrong here? And if it is supposedly a syntax error with the "|" symbol, how can it actually be fixed? The result of the affiliateBalance query needs to be a union, hence the symbol.
I’m using Apollo Server with node. Thank you
UPDATE:
The error I get with the code in my question as requested:
/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/error/syntaxError.js:15 return new _GraphQLError.GraphQLError(Syntax Error: ${description}, { ^ GraphQLError: Syntax Error: Expected Name, found "|". at syntaxError (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/error/syntaxError.js:15:10) at Parser.expectToken (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:1413:40) at Parser.parseName (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:107:24) at Parser.parseFieldDefinition (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:845:23) at Parser.optionalMany (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:1510:28) at Parser.parseFieldsDefinition (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:831:17) at Parser.parseObjectTypeDefinition (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:803:25) at Parser.parseDefinition (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:171:23) at Parser.many (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:1529:26) at Parser.parseDocument (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/language/parser.js:121:25) { path: undefined, locations: [ { line: 22, column: 30 } ], extensions: [Object: null prototype] {} }
Then if I change it to this:
import { gql } from 'apollo-server-core';
export const querySchema = gql`
type AffiliateBalance {
pendingBalance: Float!
qualifiedBalance: Float!
}
union RawAffiliateBalance = Float | AffiliateBalance
type Query {
me: User!
users(input: PaginationInput): [User!]!
user(id: Int!): User!
referrals(input: GetReferralsInput): GetReferralsResponse!
affiliateTransactions(
limit: Int
skip: Int
type: TransactionType
): GetAffiliateTransactionsResponse!
affiliatePerformanceMetrics: AffiliatePerformanceMetricsResponse!
affiliateSessions(limit: Int, skip: Int): GetAffiliateSessionsResponse!
affiliateSessionMetrics: AffiliateSessionMetricsResponse!
affiliateBalancePending: Float!
affiliateBalanceQualified: Float!
affiliateBalance: RawAffiliateBalance!
}
`;
I get this error:
/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/type/validate.js:59
throw new Error(errors.map((error) => error.message).join('\n\n'));
^
Error: Union type RawAffiliateBalance can only include Object types, it cannot include Float.
at assertValidSchema (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/type/validate.js:59:11)
at assertValidExecutionArguments (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/execution/execute.js:194:35)
at execute (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/graphql/execution/execute.js:113:3)
at generateSchemaHash (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-core/src/utils/schemaHash.ts:25:25)
at ApolloServer.generateSchemaDerivedData (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-core/src/ApolloServer.ts:716:42)
at Object.schemaDerivedDataProvider (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-core/src/ApolloServer.ts:333:18)
at new SchemaManager (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-core/src/utils/schemaManager.ts:76:36)
at new ApolloServerBase (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-core/src/ApolloServer.ts:328:24)
at new ApolloServer (/Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/node_modules/apollo-server-express/src/ApolloServer.ts:55:1)
at /Users/nick/Documents/Coding/Projects/Practice/PERNTG/server/src/index.ts:20:48
I believe you should be able to define a union type (scroll down to find the section, they did not use ids for easy hashing in the documentation)
about like this:
type AffiliateBalance {
pendingBalance: Float!
qualifiedBalance: Float!
}
union RawAffiliateBalance = Float | AffiliateBalance
type Query {
//...
affiliateBalance: RawAffiliateBalance!
update
Since Apollo gql is strictly interpreting the graphql specification (see https://github.com/graphql/graphql-spec/issues/215 ) and this has been an unresolved but actively debated issue for at least 7 years now, I suggest you might try boxing your scalar to work around the issue in graphql.
type AffiliateBalance {
pendingBalance: Float!
qualifiedBalance: Float!
}
type RawBalance {
value: Float!
}
union RawAffiliateBalance = RawBalance | AffiliateBalance
type Query {
//...
affiliateBalance: RawAffiliateBalance!
This requires revising the response payload you were hoping to serve to clients, and that may be more work than intended. Another possibility (aimed to avoid changing clients) would be to wrap it like this and expose an adapter endpoint that is not graphql and just transforms the final value for you.

Why I'm getting Validation failed (numeric string is expected)

I have this code
#Get()
#ApiQuery({
name: "code",
type: String,
required: false,
})
#ApiQuery({
name: "id",
type: Number,
required: false,
})
async read(
#Query("entity") entity: string,
#Query("code") code: string,
#Query("id", ParseIntPipe) id: number
): Promise<Q> {
return this.service.readAsync({ where: { codigo: code, id: id } });
}
Why I'm getting Validation failed (numeric string is expected) when I request to http://localhost:3000/api/v1/endpoint?entity=a&code=b
I know is related with id param, but I don't know how to solve this.
I want to be able to use code or id params according my needs.
If I request to http://localhost:3000/api/v1/endpoint?entity=a&code=b&id=1 or http://localhost:3000/api/v1/endpoint?entity=a&id=1 all is fine.
here #Query("id", ParseIntPipe) id: number you're saying that the query parameter id is required and must be an integer.
Thus, if you do GET /endpoint?entity=a&code=b, it will reply with bad request as there's no id parameter.
You can use the DefaultValuePipe pipe if id should be optional and will have a fallback value.
If you don't want any default value, then you'll need to write your own pipe (that could extends ParseIntPipe). Or you could use the builtin one ValidationPipe with class-validator decorators.
ParserIntPipe doesn't work on optional parameters, from its source code, you can see
async transform(value: string, metadata: ArgumentMetadata): Promise<number> {
if (!this.isNumeric(value)) {
throw this.exceptionFactory(
'Validation failed (numeric string is expected)',
);
}
return parseInt(value, 10);
}
/**
* #returns `true` if `value` is a valid integer number
*/
protected isNumeric(value: string): boolean {
return (
['string', 'number'].includes(typeof value) &&
/^-?\d+$/.test(value) &&
isFinite(value as any)
);
}
As per Micael Levi answer, you either provide a default value using DefaultValuePipe in case it was missing, or you build your own custom pipe that pass parameter undefined value

GraphQL Resolver Problems

I've spent quite a bit of time reading through the GraphQL tutorials but unfortunately they don't seem to cover things in quite enough depth for me to get my head around. I'd really appreciate some help with this real world example.
In the examples the queries are placed at the root of the resolver object; I can get this to work fine for single level queries. When I attempt to resolve a nested query however the nested resolver never gets called. What I'm massively confused by is every tutorial I find that isn't issued on the graphql website put in a Query object and nest their queries underneeth that, not root level.
Consider the following Schema:
type Product {
id: String!
retailerId: String!
title: String!
description: String
price: String!
currency: String!
}
type OrderLine {
product: Product!
quantity: Int!
}
type Order {
id: String!
retailerId: String!
orderDate: Date!
orderLines: [OrderLine!]!
}
type Query {
product(id: String!): Product
order(id: String!): Order
}
schema {
query: Query
}
And the following query:
query {
order(id: "1") {
id
orderLines {
quantity
}
}
}
I have tried multiple versions of implementing the resolvers (just test data for now) and none seem to return what I exect. This is my current resolver implementation:
const resolvers = {
OrderLine: {
quantity: () => 1,
},
Order: {
orderLines: (parent: any, args: any) => { console.log("Calling order lines"); return []; },
},
Query: {
product(parent, args, ctx, other) {
return { id: args.id.toString(), test: true };
},
order: ({ id }) => { console.log("Calling order 1"); return { id: id.toString(), testOrder: true, orderLines: [] }; },
},
order: ({ id }) => { console.log("Calling order 2"); return { id: id.toString(), testOrder: true, orderLines: [] }; },
};
In the console I can oberse the "Calling order 2" log message, there are no logs to "Calling order lines" and the order lines array is empty.
So two part question:
1) Why does it hit "Calling order 2" and not "Calling order 1" in the above example?
2) Why won't the above work for the nested query Order.OrderLines?
Thanks in advance!
In query
type Query {
product(id: String!): Product
order(id: String!): Order
users: User
}
schema {
query: Query
}
In resolvers
const resolvers = {
order: ({ id }) => function
product: ({ id }) => function
}
Graphql work on query resolver concept. If you want to any query(example users) you must have
resolver(ie users) which return User having definition in type User.
Graphql query is interactive and case sensitive
The next step is to implement the resolver function for the order/product query.
In fact, one thing we haven’t mentioned yet is that not only root fields,
but virtually all fields on the types in a GraphQL schema have resolver functions.
1) Why does it hit "Calling order 2" and not "Calling order 1" in the above example?
In this Query
query {
order(id: "1") {
id
orderLines {
quantity
}
}
}
then it go to order which return Order with define type
2) Why won't the above work for the nested query Order.OrderLines?
You can only use two query first order and second product only as per your schema
Please check doc for nested query for this requirement.
If you use buildSchema to generate your schema, the only way to provide resolvers for your fields is through the root object. But this is more of a hack -- you're not actually overriding the default resolvers for the fields and as such, you're basically limited to just working with the root-level fields (as you are learning the hard way). This is why only the Query.order function is called -- this is a root-level field. Why passing functions through the root (kind of) works is explained in detail here.
The bottom line is you shouldn't be using buildSchema. If you want to use SDL to define your schema, migrate to using Apollo Server.

GraphQL mutation that accepts an array of dynamic size in one request as input with NodeJs

I want to pass an object array of [{questionId1,value1},{questionId2,value2},{questionId3,value3}] of dynamic size in GraphQL Mutation with NodeJS
.........
args: {
input: {
type: new GraphQLNonNull(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
}
},
.........
How can I do that with the given sample of code?
Thanks
If you want to pass an object array with GraphQL Mutation you need to use "GraphQLList" which allows you to pass an array with dynamic size of given input.
Here is the example
........
........
args: {
input: {
type: new GraphQLNonNull(GraphQLList(new GraphQLInputObjectType({
name: 'AssessmentStep3Input',
fields: {
questionId:{
name:'Question ID',
type: new GraphQLNonNull(GraphQLID)
},
value:{
name:'Question Value',
type: new GraphQLNonNull(GraphQLBoolean)
}
}
}))
)
}
},
........
........
Hope it helps.
Thanks
i just published the article on that, so that you can take a look if you would like to know more detail. This is the repository with the examples, where the createUsers mutation is implemented https://github.com/atherosai/express-graphql-demo/blob/feature/5-modifiers/server/graphql/users/userMutations.js. You can take a look how it is implemented, but in general the above answer is correct. You can input as many objects as you would like to in the array (if you have not implemented some number of items limiting, but it is not there by default).

How do I limit the properties of a query based of a common subproperty?

Given the schema:
{
_id: ObjectID,
city:
{ units:
{ abc: {},
def: { tuid : String },
...
xxx: { tuid : String }
}
}
I would like to return, for a particular _id, all the properties of units who's subproperty tuid is, for example, 123.
I have searched for information about this but array operations keep popping up instead of what I need.
Thank you.

Resources