Getting "Cannot return null" error while querying API using Graphql? [duplicate] - graphql

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 3 years ago.
I am not sure what I am doing wrong. I cant query this that seems to be a very easy API using GraphQL?
https://data.brreg.no/enhetsregisteret/enhet.json
I have tried different solutions. But I get the same error/problem.
import { ApolloServer, gql, IResolverObject } from "apollo-server";
import fetch from "node-fetch";
const typeDefs = gql`
type Company {
organisasjonsnummer: Int
navn: String
}
type Query {
companies: [Company!]!
}
`;
const resolvers: IResolverObject = {
Query: {
companies: async () => {
const response = await fetch(
"https://data.brreg.no/enhetsregisteret/enhet.json"
);
const data = await response.json();
return data.results;
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Query used in GraphQL Playground:
{
companies{
organisasjonsnummer
}
}
Error received from GraphQL Playground:
{
"errors": [
{
"message": "Cannot return null for non-nullable field Query.companies.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"companies"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Cannot return null for non-nullable field Query.companies.",
" at completeValue (F:\\apollo-datasource-rest-example\\node_modules\\graphql\\execution\\execute.js:573:13)",
" at F:\\apollo-datasource-rest-example\\node_modules\\graphql\\execution\\execute.js:505:16",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
}
}
],
"data": null
}

Because the JSON return from that link does not have a field called "results" , so null is resolved for the companies root query but it is expected to have a non-nullable value because its schema is defined as [Company!]!.
You should return data.data from this resolver based on the JSON structure return from that link.

Related

Remove null results from a array that can contain nullable values in GraphQL

I have a query in my app that works but response is little ugly, there is probably two ways to solve this:
Write resolver differently
Clean response from null values
Here is resolver:
t.list.field('manyDevices', {
type: 'Device',
description: 'Get list of devices belonging to user',
args: {
input: nonNull(deviceIdentifierInput.asArg()),
},
resolve: async (_, { input: { id } }, { prisma }) => {
return await prisma.device.findMany({ where: { userId: id } });
},
});
This resolver looks for all devices with provided id. Id can be mine and also can be from a some other user. Devices can be public and private, and I don't want to receive private devices except if they are mine.
const isDevicePublic = rule({ cache: 'strict' })(
async ({ isPublic }: Device) => {
if (!isPublic) {
return permissionErrors.noPermission;
}
return true;
},
);
const isDeviceOwner = rule({ cache: 'strict' })(
async ({ userId }: Device, _, { user }: Context) => {
assertValue(user, permissionErrors.noAuthentication);
if (userId !== user.id) {
return permissionErrors.noPermission;
}
return true;
},
);
These are rules that I place on my schema with graphql-shield library and it works. There is just one problem, if a user have a private device it will be listed in response array as null and graphql-shield will throw error, so response can look like this:
{
"errors": [
{
"message": "You have no permission to access this resource",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": [
"manyDevices",
0,
"name"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: You have no permission to access this resource",
" at Rule.resolve (/workspace/node_modules/graphql-shield/dist/rules.js:33:24)",
" at runMicrotasks (<anonymous>)",
" at processTicksAndRejections (internal/process/task_queues.js:93:5)",
" at async Promise.all (index 0)"
]
}
}
}
],
"data": {
"manyDevices": [
null,
{
"name": "device-01"
}
]
}
}
So there is one fetched device and other that is private that throws this error, can I somehow remove null and error response or should I filter them out in resolver?

Graphql returning Cannot return null for non-nullable field Query.getDate. As I am new to graphql I want to know is my approach is wrong or my code?

I have created resolver, schema and handler which will fetch some record from dynamoDB. Now when I perform query then I am getting "Cannot return null for non-nullable field Query.getDate" error. I would like to know whether my approach is wrong or there is any change required in code.
My code : https://gist.github.com/vivek-chavan/95e7450ff73c8382a48fb5e6a5b96025
Input to lambda :
{
"query": "query getDate {\r\n getDate(id: \"0f92fa40-8036-11e8-b106-952d7c9eb822#eu-west-1:ba1c96e7-92ff-4d63-879a-93d5e397b18a\") {\r\n id\r\n transaction_date\r\n }\r\n }"
}
Response :
{
"errors": [
{
"message": "Cannot return null for non-nullable field Query.getDate.",
"locations": [
{
"line": 2,
"column": 7
}
],
"path": [
"getDate"
]
}
],
"data": null
}
Logs of lambda function :
[ { Error: Cannot return null for non-nullable field Query.getDate.
at completeValue (/var/task/node_modules/graphql/execution/execute.js:568:13)
at completeValueCatchingError (/var/task/node_modules/graphql/execution/execute.js:503:19)
at resolveField (/var/task/node_modules/graphql/execution/execute.js:447:10)
at executeFields (/var/task/node_modules/graphql/execution/execute.js:293:18)
at executeOperation (/var/task/node_modules/graphql/execution/execute.js:237:122)
at executeImpl (/var/task/node_modules/graphql/execution/execute.js:85:14)
at execute (/var/task/node_modules/graphql/execution/execute.js:62:229)
at graphqlImpl (/var/task/node_modules/graphql/graphql.js:86:31)
at /var/task/node_modules/graphql/graphql.js:32:223
at graphql (/var/task/node_modules/graphql/graphql.js:30:10)
message: 'Cannot return null for non-nullable field Query.getDate.',
locations: [Object],
path: [Object] } ],
data: null }
2019-02-25T10:07:16.340Z 9f75d1ea-2659-490b-ba59-5289a5d18d73 { Item:
{ model: 'g5',
transaction_date: '2018-07-05T09:30:31.391Z',
id: '0f92fa40-8036-11e8-b106-952d7c9eb822#eu-west-1:ba1c96e7-92ff-4d63-879a-93d5e397b18a',
make: 'moto' } }
Thanks in advance!
This is your code:
const data = {
getDate(args) {
var params = {
TableName: 'delete_this',
Key: {
"id": args.id
}
};
client.get(params, function(err,data){
if(err){
console.log('error occured '+err)
}else{
console.log(data)
}
});
},
};
const resolvers = {
Query: {
getDate: (root, args) => data.getDate(args),
},
};
You're seeing that error because getDate is a a Non-Null field in your schema, but it is resolving to null. Your resolver needs to return either a value of the appropriate type, or a Promise that will resolve to that value. If you change data like this
const data = {
getDate(args) {
return {
id: 'someString',
transaction_date: 'someString',
}
}
}
you'll see the error go away. Of course, your goal is to return data from your database, so we need to add that code back in. However, your existing code utilizes a callback. Anything you do inside the callback is irrelevant because it's ran after your resolver function returns. So we need to use a Promise instead.
While you can wrap a callback with Promise, that shouldn't be necessary with aws-sdk since newer versions support Promises. Something like this should be sufficient:
const data = {
getDate(args) {
const params = //...
// must return the resulting Promise here
return client.get(params).promise().then(result => {
return {
// id and transaction_date based on result
}
})
}
}
Or using async/await syntax:
const data = {
async getDate(args) {
const params = //...
const result = await client.get(params).promise()
return {
// id and transaction_date based on result
}
}
}

how to return customize data in prisma subscription

I am learning graphql & prisma and I came across a question on prisma subscription.
I want to return an item list whenever there is a creation or update on Item. So this is my code which not works.
scheme.graphql
# import Item from "./generated/prisma.graphql"
type Subscription {
todoItems: TodoItems
}
type TodoItems {
items: [Item!]!
}
resolver
const Subscription = {
todoItems: {
subscribe: async (parent, args, context, info) => {
const itemSubscription = await context.db.subscription.item({
where: { mutation_in: ['CREATED', 'UPDATED'] },
}, info);
return itemSubscription;
},
resolve: async (payload, args, context, info) => {
const items = await context.db.query.items({ type: 0, orderBy: 'updatedAt_DESC' }, info);
return { items };
},
},
}
module.exports = {
Subscription,
}
and in graphql playground,
subscription{
todoItems{
items{
title
}
}
}
it gives the error:
{
"errors": [
{
"message": "Anonymous Subscription must select only one top level field.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"todoItems"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Anonymous Subscription must select only one top level field.",
" at asErrorInstance (d:\\git\\inote\\node_modules\\graphql\\execution\\execute.js:489:43)",
" at <anonymous>",
" at process._tickCallback (internal/process/next_tick.js:118:7)"
]
}
}
}
]
}
Any idea?
Prisma does not support subscribing item lists. Instead, prisma wants you to subscribe to single item mutations ("created", "updated", "deleted"). As described here.
E.g.
subscription newTodos {
todo(where: {
mutation_in: [CREATED]
}) {
mutation
node {
title
}
}
}
To get "the full list", you have to query on the todos after subscribing to avoid missing events (race condition). As a result you have to manually "sync" the data from the subscription and your query.

I need Apollo GraphQL to send back http responses

I'd like for the ability to have my express graphQL server to send back the HTTP status code along with the response to the client. At the moment, all I see is data, however, additional functionality based on the status code would be helpful.
I don't see anything here, unless I'm looking in the wrong place:
http://dev.apollodata.com/tools/graphql-server/setup.html
For Apollo Server 2.2.x and later, we can use plugins to custom the HTTP status code. Custom the HTTP status code in willsendresponse event handler. You can check the errors array and set the corresponding HTTP status code for different type of error.
E.g.
server.ts:
import { ApolloServer, gql } from 'apollo-server';
import { ApolloServerPlugin } from 'apollo-server-plugin-base';
function customHTTPStatusPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
return {
willSendResponse({ errors, response }) {
if (response && response.http) {
if (errors) {
response.data = undefined;
response.http.status = 500;
}
}
},
};
},
};
}
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello() {
throw new Error('something happened');
},
},
};
const server = new ApolloServer({ typeDefs, resolvers, plugins: [customHTTPStatusPlugin()] });
const port = 3000;
server.listen(port).then(({ url }) => console.log(`Server is ready at ${url}`));
The response:
{
"error": {
"errors": [
{
"message": "something happened",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"hello"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: something happened",
" at hello (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/src/stackoverflow/40387508/server.ts:30:13)",
" at field.resolve (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/apollo-server-express/node_modules/graphql-extensions/src/index.ts:274:18)",
" at field.resolve (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/apollo-server-express/node_modules/apollo-server-core/src/utils/schemaInstrumentation.ts:103:18)",
" at resolveFieldValueOrError (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:467:18)",
" at resolveField (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:434:16)",
" at executeFields (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:275:18)",
" at executeOperation (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:219:122)",
" at executeImpl (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:104:14)",
" at Object.execute (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql/execution/execute.js:64:35)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/apollo-server-express/node_modules/apollo-server-core/src/requestPipeline.ts:548:22"
]
}
}
}
]
}
}
You will also get the HTTP status code - 500 Internal Server Error at the client-side.

GraphQL how to mutate data

I have a basic schema for mutating some data which looks like
const schema = new graphql.GraphQLSchema({
mutation: new graphql.GraphQLObjectType({
name: 'Remove',
fields: {
removeUser: {
type: userType,
args: {
id: { type: graphql.GraphQLString }
},
resolve(_, args) {
const removedData = data[args.id];
delete data[args.id];
return removedData;
},
},
},
})
});
Looking around google I cant find a clear example of the example query which needs to be sent to mutate.
I have tried
POST -
localhost:3000/graphql?query={removeUser(id:"1"){id, name}}
This fails with error:
{
"errors": [
{
"message": "Cannot query field \"removeUser\" on type \"Query\".",
"locations": [
{
"line": 1,
"column": 2
}
]
}
]
}
In order to post requests from the front-end application it is recommended to use apollo-client package. Say i wanted to validate a user login information:
import gql from 'graphql-tag';
import ApolloClient, {createNetworkInterface} from 'apollo-client';
client = new ApolloClient({
networkInterface: createNetworkInterface('http://localhost:3000/graphql')
});
remove(){
client.mutate({
mutation: gql`
mutation remove(
$id: String!
) {
removeUser(
id: $id
){
id,
name
}
}
`,
variables: {
id: "1"
}
}).then((graphQLResult)=> {
const { errors, data } = graphQLResult;
if(!errors && data){
console.log('removed successfully ' + data.id + ' ' + data.name);
}else{
console.log('failed to remove');
}
})
}
More information about apollo-client can be found here
Have you tried using graphiql to query and mutate your schema?
If you'd like to create a POST request manually you might wanna try to struct it in the right form:
?query=mutation{removeUser(id:"1"){id, name}}
(Haven't tried POSTing myself, let me know if you succeeded, i structured this out of the url when using graphiql)
You have to explicitly label your mutation as such, i.e.
mutation {
removeUser(id: "1"){
id,
name
}
}
In GraphQL, if you leave out the mutation keyword, it's just a shorthand for sending a query, i.e. the execution engine will interpret it as
query {
removeUser(id: "1"){
id,
name
}
}
cf. Section 2.3 of the GraphQL Specification
const client = require("../common/gqlClient")();
const {
createContestParticipants,
} = require("../common/queriesAndMutations");
const gql = require("graphql-tag");
const createPartpantGql = async (predictObj) => {
try {
let resp = await client.mutate({
mutation: gql(createContestParticipants),
variables: {
input: {
...predictObj,
},
},
});
let contestParticipantResp = resp.data.createContestParticipants;
return {
success: true,
data: contestParticipantResp,
};
} catch (err) {
console.log(err.message)
console.error(`Error creating the contest`);
return {
success: false,
message: JSON.stringify(err.message),
};
}
};

Resources