graphql query with args not working for user id - graphql

I am bamboozled. I initially created the user query and it was giving me errors that I assumed were syntax errors. But then I created an identical query for vehicles which works perfectly. I have a suspicion that it's related to the ID! type but I have run out of leads. Any help would be appreciated!
Here are my typedefs and resolvers.
//TYPEDEFS//
type User {
id: ID!
fname: String
lname: String
email: String
password: String
vehicles: [Vehicle]
}
type Vehicle {
id: ID!
vin: String
model: String
make: String
drivers: [User]
}
type Query {
users: [User]
user(id: ID!): User
vehicles: [Vehicle]
vehicle(vin: String): Vehicle
}
//RESOLVERS//
user: async (parent, args, context) => {
const { id } = args
return context.prisma.user.findUnique({
where: {
id,
},
})
},
vehicle: async (parent, args, context) => {
const { vin } = args
return context.prisma.vehicle.findUnique({
where: {
vin,
}
})
}
//QUERY//
**This one is the broken one and has the error: Got invalid value '1' on prisma.findOneUser. Provided String, expected Int
**I've tried doing id: "1" and user(where: {id: 1})
query {
user(id:1){
id
fname
}
}
**This one works as intended
query {
vehicle(vin:"123123123"){
vin
make
}
}
//FULL ERROR*//
{
"errors": [
{
"message": "\nInvalid `prisma.user.findUnique()` invocation:\n\n{\n where: {\n id: '1'\n ~~~\n }\n}\n\nArgument id: Got invalid value '1' on prisma.findOneUser. Provided String, expected Int.\n\n",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"user"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"clientVersion": "2.13.1",
"stacktrace": [
"Error: ",
"Invalid `prisma.user.findUnique()` invocation:",
"",
"{",
" where: {",
" id: '1'",
" ~~~",
" }",
"}",
"",
"Argument id: Got invalid value '1' on prisma.findOneUser. Provided String, expected Int.",
"",
"",
" at Document.validate (/home/atran/workspace/m4m/m4m_server/node_modules/#prisma/client/runtime/index.js:76090:19)",
" at NewPrismaClient._executeRequest (/home/atran/workspace/m4m/m4m_server/node_modules/#prisma/client/runtime/index.js:77796:17)",
" at resource.runInAsyncScope (/home/atran/workspace/m4m/m4m_server/node_modules/#prisma/client/runtime/index.js:77733:52)",
" at AsyncResource.runInAsyncScope (async_hooks.js:188:21)",
" at NewPrismaClient._request (/home/atran/workspace/m4m/m4m_server/node_modules/#prisma/client/runtime/index.js:77733:25)",
" at Object.then (/home/atran/workspace/m4m/m4m_server/node_modules/#prisma/client/runtime/index.js:77850:39)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
}
}
],
"data": {
"user": null
}
}

Prisma expects an Int:
"Argument id: Got invalid value '1' on prisma.findOneUser. Provided
String, expected Int.",
Therefore you need to cast id to a number. Maybe something like this:
user: async (parent, args, context) => {
const id = +args.id;
return context.prisma.user.findUnique({
where: { id }
});
}

Related

How do I see the name of a logged in user?

I'm trying to access the current logged in user's name, and get it working in the Playground right now for apollo graphql. I'm using Prisma and I'm a beginner.
This is my schema.graphql:
type Query {
info: String!
userlist: [User!]!
me: User
}
type Mutation {
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
}
Here is my src/resolvers/Query.js:
const { getUserId } = require("../utils");
function userlist(parent, args, context) {
return context.prisma.user.findMany();
}
function me(parent, args, context) {
const id = getUserId(context);
return context.prisma.user({ id });
}
module.exports = {
userlist,
me,
};
How do I test this in the playground? If I log in a user with this query:
mutation {
login(email: "alice#prisma.io", password: "graphql") {
token
user {
email
}
}
}
Then when I try to display "me" I get this:
query {
me {
id
name
}
}
Result:
{
"errors": [
{
"message": "Cannot read properties of undefined (reading 'authorization')",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"me"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read properties of undefined (reading 'authorization')",
" at getUserId (/Users/username/example-3/server/src/utils.js:10:36)",
" at me (/Users/username/example-3/server/src/resolvers/Query.js:8:14)",
// i deleted a bunch of stuff here, let me know if you would like to see it and I'll add it back
]
}
}
}
],
"data": {
"me": null
}
}
This is the utils.js:
const jwt = require("jsonwebtoken");
const APP_SECRET = "GraphQL-is-aw3some";
function getTokenPayload(token) {
return jwt.verify(token, APP_SECRET);
}
function getUserId(req, authToken) {
if (req) {
const authHeader = req.headers.authorization;
if (authHeader) {
const token = authHeader.replace("Bearer ", "");
if (!token) {
throw new Error("No token found");
}
const { userId } = getTokenPayload(token);
return userId;
}
} else if (authToken) {
const { userId } = getTokenPayload(authToken);
return userId;
}
throw new Error("Not authenticated");
}
module.exports = {
APP_SECRET,
getUserId,
};
Do I need to pass in the auth token somehow? Any idea why getUserId isn't working? I think I have something wrong, because the code I was using from an example has getUserId(req), but another solution I saw has getUserId(context), so is that what is wrong here? How do I change my Query to use req instead of context? I'm not understanding them enough to make this change.
You answered your own question:
Do I need to pass in the auth token somehow?
Yes. You're getting an error because you're not passing any headers from the playground so req.headers is undefined.
At the bottom left of the playground there's an area where you can define query variables and headers. Define one called "authorization" and put a valid token in the contents.
You should have a login method somewhere that creates a valid token, use that.

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?

Cannot return null for non-nullable field , Debugger dosen't show null [duplicate]

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 2 years ago.
I have this schema.graphql
### This file was generated by Nexus Schema
### Do not make changes to this file directly
type AuthPayload {
token: String!
users: users!
}
scalar DateTime
type Mutation {
login(email: String, password: String): AuthPayload!
signup(CREATED_BY: String, EMAIL: String, FIRST_NAME: String, IS_ACTIVE: Boolean, PASSWORD: String, USERNAME: String): AuthPayload!
}
type Query {
me: users
}
type users {
CREATED_BY: String!
CREATED_ON: DateTime
EMAIL: String!
FIRST_NAME: String!
id: Int!
IS_ACTIVE: Boolean!
LAST_NAME: String
MODIFIED_BY: String
MODIFIED_ON: DateTime
ORGANIZATION_ID: String
PASSWORD: String!
PHONE: String
USERNAME: String!
}
mutations :-
const Mutation = mutationType({
definition(t) {
t.field('signup', {
type: 'AuthPayload',
args: {
FIRST_NAME: stringArg({ nullable: true }),
EMAIL: stringArg(),
PASSWORD: stringArg(),
IS_ACTIVE: booleanArg(),
USERNAME: stringArg(),
CREATED_BY: stringArg(),
},
resolve: async (parent, { FIRST_NAME, EMAIL, PASSWORD ,IS_ACTIVE ,USERNAME,CREATED_BY }, ctx) => {
const hashedPassword = await hash(PASSWORD, 10)
const user = await ctx.prisma.users.create({
data: {
FIRST_NAME,
EMAIL,
PASSWORD: hashedPassword,
IS_ACTIVE,
USERNAME,
CREATED_BY
},
})
return {
token: sign({ userId: user.id }, APP_SECRET),
user,
}
},
})
t.field('login', {
type: 'AuthPayload',
args: {
email: stringArg(),
password: stringArg(),
},
resolve: async (parent, { email, password }, context) => {
const user = await context.prisma.users.findOne({
where: {
EMAIL : email,
},
})
if (!user) {
return new Error(`No user found for email: ${email}`)
}
const passwordValid = await compare(password, user.PASSWORD)
if (!passwordValid) {
return new Error('Invalid password')
}
const token = await sign({ userId: user.id }, APP_SECRET)
return {
token ,
user,
}
},
})
},
})
My problem is when i try to mutate the login method with token return value , it works perfectly and here is my mutation
mutation{
login(email :"dondala422#hotmail.com" password :"aa")
{
token
}
}
Response
{
"data": {
"login": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMyLCJpYXQiOjE1OTcxMDY0OTd9.d1Ra32ArCXumBfzg2vE1-xeea21cAkNwWBJPm3U3akM"
}
}
}
As shown . this works perfectly . now as mentioned the AuthPayload return the token and the users type
when i try to mutate with user :-
mutation{
login(email :"dondala422#hotmail.com" password :"aa")
{
token
users{
USERNAME
FIRST_NAME
}
}
}
it gives me this error
{
"errors": [
{
"message": "Cannot return null for non-nullable field AuthPayload.users.",
"locations": [
{
"line": 4,
"column": 5
}
],
"path": [
"login",
"users"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Cannot return null for non-nullable field AuthPayload.users.",
" at completeValue (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:595:13)",
" at completeValueCatchingError (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:530:19)",
" at resolveField (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:461:10)",
" at executeFields (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:297:18)",
" at collectAndExecuteSubfields (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:748:10)",
" at completeObjectValue (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:738:10)",
" at completeValue (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:626:12)",
" at completeValue (C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:592:21)",
" at C:\\Users\\donda\\Desktop\\New folder (3)\\prisma-examples\\javascript\\graphql-auth - Copy\\node_modules\\graphql\\execution\\execute.js:527:16"
]
}
}
}
],
"data": null
}
i tried to attach the debugger to see where is the null occur
and i didn't found any nullable values
here is a picture of vscode before return value , the token and user object are defined
VSCode Debugger picture
The object returned inside your resolver includes a property named user, but your field is named users. Since users is undefined, it resolves to null, but the field is non-nullable, so an error is thrown instead.

How to pass nested variables to the GraphQL query in Apollo?

Trying to pass nested variables to the GraphQL query but my server gets only top-level variables (shopId), everything else is null.
I tried:
#1
const CALCULATE_PACKAGE_PRICE = gql`
query CalculatePackagePrice(
$shopId: String!
$address1: String
$zip: String
$city: String
$countryCode: String
) {
calculatePackagePrice(
where: {
shopId: $shopId
destination: {
address1: $address1
zip: $zip
city: $city
countryCode: $countryCode
}
}
) {
name
price
userErrors {
field
message
}
}
}
`
const [calculatePackagePrice, { loading, data }] = useLazyQuery(
CALCULATE_PACKAGE_PRICE,
{
variables: {
shopId: shopId,
destination: {
address1: "Example 123",
zip: "123",
city: "Test",
countryCode: "US",
},
},
}
)
And #2:
export function CALCULATE_PACKAGE_PRICE({ shopId, destination }) {
return gql`
query CalculatePackagePrice {
calculatePackagePrice(
where: {
shopId: "${shopId}"
destination: {
address1: "${destination.address1}"
zip: "${destination.zip}
city: "${destination.city}"
countryCode: "${destination.countryCode}"
}
}
) {
name
price
userErrors {
field
message
}
}
}
`
}
const [calculatePackagePrice, { loading, data }] = useLazyQuery(
CALCULATE_PACKAGE_PRICE({
shopId: shopId,
destination: {
address1: "Example 123",
zip: "123",
city: "Test",
countryCode: "US",
},
})
)
It works just fine when I hardcoded variables content to the queries. What I'm doing wrong?
Here is a helpful snippet from graphql docs,
All declared variables must be either scalars, enums, or input object types. So if you want to pass a complex object into a field, you need to know what input type that matches on the server.
You're correctly passing in the variables as strings, but then trying (perhaps successfully, but I've never seen the syntax before) to create the object in the gql template string. Instead, create an input type for destination and where.
input WhereInput {
shopId: String!
destination: DestinationInput!
}
input DestinationInput {
address1: String!
zip: String!
city: String!
countryCode: String!
}
then change the query on the client (and update the server definition),
const CALCULATE_PACKAGE_PRICE = gql`
query CalculatePackagePrice($where: WhereInput!) {
calculatePackagePrice(where: $where) {
name
price
userErrors {
field
message
}
}
}
`
then pass the variables like,
const [calculatePackagePrice, { loading, data }] = useLazyQuery(
CALCULATE_PACKAGE_PRICE,
{
variables: {
where: {
shopId,
destination: {
address1: "Example 123",
zip: "123",
city: "Test",
countryCode: "US",
},
},
}
}
)

Apollo GraphQL tutorial: "GraphQLError: Cannot query field \"id\" on type \"LaunchConnection\"."

I'm trying to follow the Apollo GraphQL tutorial at this step, https://www.apollographql.com/docs/tutorial/resolvers/#run-queries-in-the-playground. Following https://github.com/apollographql/fullstack-tutorial, I ran
cd final/server && npm i && npm start
as well as
cd final/client && npm i && npm start
(For the final/server, I first deleted the package-lock.json before running npm install because I was running into issues with the sqlite3 dependency).
However, in the GraphQL playground on localhost:4000, if I try to run the query
query GetLaunches {
launches {
id
mission {
name
}
}
}
I get the error response
{
"error": {
"errors": [
{
"message": "Cannot query field \"id\" on type \"LaunchConnection\".",
"locations": [
{
"line": 3,
"column": 5
}
],
"extensions": {
"code": "GRAPHQL_VALIDATION_FAILED",
"exception": {
"stacktrace": [
"GraphQLError: Cannot query field \"id\" on type \"LaunchConnection\".",
" at Object.Field (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:64:31)",
" at Object.enter (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:334:29)",
" at Object.enter (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:385:25)",
" at visit (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:252:26)",
" at Object.validate (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/validation/validate.js:63:22)",
" at validate (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)",
" at Object.<anonymous> (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)",
" at Generator.next (<anonymous>)",
" at fulfilled (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)",
" at processTicksAndRejections (internal/process/task_queues.js:93:5)"
]
}
}
},
{
"message": "Cannot query field \"mission\" on type \"LaunchConnection\".",
"locations": [
{
"line": 4,
"column": 5
}
],
"extensions": {
"code": "GRAPHQL_VALIDATION_FAILED",
"exception": {
"stacktrace": [
"GraphQLError: Cannot query field \"mission\" on type \"LaunchConnection\".",
" at Object.Field (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:64:31)",
" at Object.enter (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:334:29)",
" at Object.enter (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:385:25)",
" at visit (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:252:26)",
" at Object.validate (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/graphql/validation/validate.js:63:22)",
" at validate (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)",
" at Object.<anonymous> (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)",
" at Generator.next (<anonymous>)",
" at fulfilled (/Users/kurt/Documents/Scratch/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)",
" at processTicksAndRejections (internal/process/task_queues.js:93:5)"
]
}
}
}
]
}
}
(See screenshot below).
Any idea what is causing this? I do see a GraphQL schema in the right pop-up window which appears to contain these fields:
directive #cacheControl(
maxAge: Int
scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE
enum CacheControlScope {
PUBLIC
PRIVATE
}
type Launch {
id: ID!
site: String
mission: Mission
rocket: Rocket
isBooked: Boolean!
}
type LaunchConnection {
cursor: String!
hasMore: Boolean!
launches: [Launch]!
}
type Mission {
name: String
missionPatch(size: PatchSize): String
}
type Mutation {
bookTrips(launchIds: [ID]!): TripUpdateResponse!
cancelTrip(launchId: ID!): TripUpdateResponse!
login(email: String): String
}
enum PatchSize {
SMALL
LARGE
}
type Query {
launches(
pageSize: Int
after: String
): LaunchConnection!
launch(id: ID!): Launch
me: User
}
type Rocket {
id: ID!
name: String
type: String
}
type TripUpdateResponse {
success: Boolean!
message: String
launches: [Launch]
}
scalar Upload
type User {
id: ID!
email: String!
trips: [Launch]!
}
Looking at the schema you provided, Query launches returns type LaunchConnection
type LaunchConnection {
cursor: String!
hasMore: Boolean!
launches: [Launch]!
}
type Query {
launches: LaunchConnection!
}
Your query, below, is expected to return type LaunchConnection
query GetLaunches {
launches {
id
mission {
name
}
}
}
But LaunchConnection has fields cursor, hasMore & launches. You are asking for fields id & mission on the incorrect type. You should first dive into the launches field on LaunchConnection then you can ask for fields on the Launch type. Your query should look like the following:
query GetLaunches {
launches {
launches {
id
mission {
name
}
}
}
}

Resources