Singular and Plural Fields in GraphQL


This is part of a series about decisions my team made with our GraphQL schema. Check out that post for context, or to read about other decisions we made.

Pretty much every API needs to support an access pattern where you need to be able to query for a single user, and you also need to query for multiple users. (Replace “user” with any type of data your application models.) I played around with a few ways to handle this, and ended up putting both a singluar and a plural field of the same type at the same level of the schema. The singular field has a required primary key argument and is used to look up a specific record. The plural field returns all records of that type by default, but includes an optional argument that can be used to filter the results. Here’s an example with a User type:

Schema

type User {
  id: ID!
  name: String!
}

type Query {
  # `id` is a required argument for the singular `user` field,
  # used to search for a specific user
  user(id: ID!): User

  # `ids` is an optional array argument for the plural `users` field.
  # Not providing it will make the API return all users
  # to which the requester has access.
  users(ids: [ID!]): [User!]!
}

Request

{
  user(id: 51) {
    id
    name
  }

  # Note that these next two fields are both the same `users` field,
  # and I'm just aliasing them to the names `someUsers` and `allUsers`.
  someUsers: users(ids: [52, 53]) {
    id
    name
  }

  allUsers: users {
    id
    name
  }
}

Response

{
  "data": {
    "user": {
      "id": "51",
      "name": "Michael Scott"
    },
    "someUsers": [
      {
        "id": "52",
        "name": "Jim Halpert"
      },
      {
        "id": "53",
        "name": "Pam Beesly"
      }
    ],
    "allUsers": [
      {
        "id": "51",
        "name": "Michael Scott"
      },
      {
        "id": "52",
        "name": "Jim Halpert"
      },
      {
        "id": "53",
        "name": "Pam Beesly"
      },
      {
        "id": "54",
        "name": "Dwight Schrute"
      }
    ]
  }
}
© 2024 Sean Gransee