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

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
}
}
}
}

Related

How to merge a type whose fields come from two different GraphQL subschemas?

I'm running a gateway with apollo-server v2 with graphql-tools v7 and have the following services and subschemas, which I've set up as a (contrived) proof-of-concept:
Service 1:
Query {
getUser(input: GetUserInput!): User
}
input GetUserInput {
id: ID!
}
type User {
id: ID!
contacts: Contacts
}
type Contacts {
id: ID!
primary: String
}
Service 2:
Query {
getUser(input: GetUserInput!): User
}
input GetUserInput {
id: ID!
}
type User {
id: ID!
contacts: Contacts
}
type Contacts {
id: ID!
secondary: String
}
The gateway has the combined schema like this:
Query {
getUser(input: GetUserInput!): User
}
input GetUserInput {
id: ID!
}
type User {
id: ID!
contacts: Contacts
}
type Contacts {
id: ID!
primary: String
secondary: String
}
The gateway is configured to stitch the schemas and merge the User type like this:
import { stitchSchemas } from "#graphql-tools/stitch"
...
const schema = stitchSchemas({
subschemas: [
{
schema: service1Schema,
executor: service1Executor,
merge: {
User: {
fieldName: "getUser",
selectionSet: "{ id }",
args: (originalObject) => ({
input: {
id: originalObject.id
}
}),
},
}
},
{
schema: service2Schema,
executor: service2Executor,
merge: {
User: {
fieldName: "getUser",
selectionSet: "{ id }",
args: (originalObject) => ({
input: {
id: originalObject.id
}
}),
},
}
},
]
})
However, when I send a query to fetch the contacts field for a User, only Service 2 is called by the gateway. Instead, I would have expected the gateway to call Service 1 to get its representation of User.contacts and also Service 2 to get its representation of User.contacts and then merge the two into a combined result.
The query I executed:
query GetContacts {
getUser(input: { id: "123" }) {
contacts {
primary
secondary
}
}
}
The result I got (and I see in logs that Service 1 was not called at all):
{
"data": {
"getUser": {
"contacts": {
"primary": null,
"secondary": "Secondary contact from Service 2"
}
}
}
}
The result I expected:
{
"data": {
"getUser": {
"contacts": {
"primary": "Primary contact from Service 1", <-- This should be included in the result.
"secondary": "Secondary contact from Service 2"
}
}
}
}
I have confirmed that I'm able to fetch other fields (e.g. User.name) from Service 1 successfully, so the subschema for Service 1 is configured correctly on the gateway (though probably not the merge options for it).
Since this is similar to the example from the graphql-tools documentation, I'm confused about why the fields of the Contacts type aren't merged as expected in the query response.

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.

graphql query with args not working for user id

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 }
});
}

How to write graphql query wiith custom objects

The server side of graphql is with nodejs and express. This is the schema for graphql. It has one query which accepts DateT object having from and to dates.
var schema = buildSchema(`
type Query {
courseWithDate(
timeFilter: DateT
): Course
},
type Course {
...
from: String
to: String
},
type DateT{
from : String
to : String
}
`);
and this is how I am getting courses
I am able to run the application with this url
localhost:4000/graphql
This is the query I am using
query courseWithDate($from: dateFrom, $to: dateTo) {
courseWithDate(timeFilter: {
from: "${dateFrom}"
to: "${dateTo}"
}) {
title
...
}
}
with these parameters
{
"from": "2019-10-10","to":"2019-10-10"
}
Exception message I get is related to the input type I am trying to pass.
{
"errors": [
{
"message": "The type of Query.courseWithDate(timeFilter:) must be Input Type but got: DateT.",
"locations": [
{
"line": 6,
"column": 25
}
]
}
]
}
I'm not sure, but probably this style looks more like best practice
type Course {
id: Int
title: String
author: String
from: String
to: String
description: String
topic: String
url: String
}
input DateInput {
dateFrom: String!
dateTo: String!
}
type Query {
courseWithDate(input: DateInput!, name: String!): Course
}
And Query on client side should be:
{
courseWithDate(input: {
dateFrom: "${dateFrom}"
dateTo: "${dateTo}"
}
name: "${name}")
{
id
name
}
}

How to set the Apollo GraphQL server to accept an object as a variable to a mutation?

Currently, I'm trying to pass an object as a variable to a mutation as shown below:
type ShopLocation {
lane1: String
lane2: String
city: String
postalCode: String
country: String
}
type ShopResponse {
statusCode: Int
messageCode: String
data: String
}
type Mutation {
createShop(
name: String
email: String
location: ShopLocation
): ShopResponse
}
But I get the following error:
{
"error": {
"errors": [
{
"message": "The type of Mutation.createShop(location:) must be Input Type but got: ShopLocation.",
"extensions": {
"code": "GRAPHQL_VALIDATION_FAILED",
"exception": {
"stacktrace": [
"Error: The type of Mutation.createShop(location:) must be Input Type but got: ShopLocation.",
" at assertValidSchema (.../node_modules/graphql/type/validate.js:71:11)",
" at Object.validate (.../node_modules/graphql/validation/validate.js:55:35)",
" at Promise.resolve.then (.../node_modules/apollo-server-core/src/runQuery.ts:188:30)",
" at <anonymous>",
" at process._tickDomainCallback (internal/process/next_tick.js:228:7)"
]
}
}
}
]
}
}
Any idea how to properly do this?
You need to make the ShopLocation with input keyword instead of type,
input ShopLocationInput {
lane1: String
lane2: String
city: String
postalCode: String
country: String
}
type ShopResponse {
statusCode: Int
messageCode: String
data: String
}
type Mutation {
createShop(
name: String
email: String
location: ShopLocationInput
): ShopResponse
}

Resources