next.jsgraphqlapolloapollo-clientapollo-server

Apollo Server query status code 400 error


Trying to make a Nextjs app with apollo, graphql and prisma. When I'm trying to query users on my front end, I'm getting a 400 error. The query works in apollo studio / sandbox so I have no idea how to fix it.

error.message: Response not successful: Received status code 400 And nothing in the server log.

schema.ts:

export const  typeDefs = gql`
    type User {
        id: String
        name: String
        email: String
        image: String
    }

    type Query {
        AllUsersQuery: [User]!
    }

my resolver.ts:

export const resolvers = {
    Query: {
        AllUsersQuery: async (_parent: any, __args: any, context: any) => await context.prisma.user.findMany(),
    },
};

And where I'm calling it from board.tsx:


const AllUsersQuery = gql`
  query {
      user{
        id
        name
        email
      }
  }
`

const Board = () => {
  const { data, loading, error } = useQuery(AllUsersQuery);

  if (loading) return <div> Loading... </div>
  if (error) return <div> Oops something went wrong: {error.message}</div>

  return (
    <>
      <div>{data?.user.email}</div>
    </>
  )
}

export default Board

response/request header:

XHRPOSThttp://localhost:3000/api/graphql
[HTTP/1.1 400 Bad Request 13ms]

    
POST
    http://localhost:3000/api/graphql
Status
400
Bad Request
VersionHTTP/1.1
Transferred766 B (1.21 kB size)
Referrer Policystrict-origin-when-cross-origin

        
    HTTP/1.1 400 Bad Request

    Access-Control-Allow-Origin: *

    Access-Control-Allow-Credentials: true

    Content-Type: application/json

    Vary: Accept-Encoding

    Content-Encoding: gzip

    Date: Sun, 02 Oct 2022 03:20:09 GMT

    Connection: keep-alive

    Keep-Alive: timeout=5

    Transfer-Encoding: chunked
        
    POST /api/graphql HTTP/1.1

    Host: localhost:3000

    User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0

    Accept: */*

    Accept-Language: en-CA,en-US;q=0.7,en;q=0.3

    Accept-Encoding: gzip, deflate, br

    Referer: http://localhost:3000/board

    content-type: application/json

    Content-Length: 91

    Origin: http://localhost:3000

    Connection: keep-alive

    Cookie: _ga=GA1.1.1971964746.1663710154; next-auth.csrf-token=33c501d5216dea4b6a029d34c13d640814228810867843882008780ce09eb536%7C83d7939882d2f38e49f72a501e895459abb7fbac2fbab0d106c6462fe35cbe7e; next-auth.callback-url=http%3A%2F%2Flocalhost%3A3000%2Flogin; next-auth.session-token=c7358df1-2605-4a34-bb5d-a1091a00b871

    Sec-Fetch-Dest: empty

    Sec-Fetch-Mode: cors

    Sec-Fetch-Site: same-origin

What am I doing wrong? Thanks


Solution

  • It appears you need to clean and flip some naming conventions. You likely want to define a resolver on your root Query type simply as users, which in turn is the field you'll access on the returned optional (data) on execution. Defining the query in this way provides flexibility; for example perhaps you add a filter arg in the future with a simple id or more complex input type. In the case, the lack of flexibility becomes evident.

    export const  typeDefs = gql`
        type User {
            id: String
            name: String
            email: String
            image: String
        }
    
        type Query {
           users: [User]!
        }
    
      // update resolver to reflect schema change on Query
      Query: {
           users: async (_parent: any, __args: any, context: any) => await context.prisma.user.findMany(),
        },
    
    
    

    Now, for your (currently filterless) query operation it makes sense to declare AllUsersQuery, an accurate description of your client implementation. In the case you added an arg to fetch a subset (which would require updating resolver to something like users(ids: [String]): [User], a different naming convention could be provided for the operation (UsersByIdsQuery)

    const AllUsersQuery = gql`
      query {
          users {
            id
            name
            email
          }
      }
    `
    
    const Board = () => {
      const { data, loading, error } = useQuery(AllUsersQuery);
    
      if (loading) return <div> Loading... </div>
      if (error) return <div> Oops something went wrong: {error.message}</div>
    
      return (
        <>
          <div>{data?.users.email}</div>
        </>
      )
    }
    
    export default Board
    

    If you wanted to leave your schema, resolver, and operation as is, you would need to update the field requested on your query as reflected in your schema, and similarly access that field on the data optional in your code.

    const AllUsersQuery = gql`
      query {
         AllUsersQuery {
            id
            name
            email
          }
      }