Best practices for GraphQL clients
Best practices for developing quality APIs at Indeed.
As a GraphQL client, follow these best practices.
Request only the data that you need
GraphQL enables clients to request exactly the data that they need.
Do not request all, or a predefined set of, fields that your client does not use.
With GraphQL, Indeed can observe the usage of fields. If clients request fields that they don't use, this interferes with our analytics and makes it harder to determine whether to deprecate a field.
Give your GraphQL operations unique, descriptive names
GraphQL enables you to name operations with a descriptive name. Use Pascal case in your descriptive names.
Self-documenting operation names communicate the meaning and context of your API to service implementers, which is powerful information, especially during schema changes.
Understand how operation naming works with GraphQL client libraries. When not used properly, libraries can give each invocation of the same named operation a dynamic unique name, which has a negative impact on observability capabilities.
Recommended
query FetchJobForHomepageModal($id: ID) { job(id: $id) { result { title } }}Not recommended
query($id: ID) { job(id: $id) { result { title } }}Use variables for arguments in GraphQL requests
A GraphQL client can use variables to substitute different values for a literal in an operation.
Variables enable reuse of client-defined operations.
Back-end systems benefit because GraphQL servers parse and validate each permutation, and prevent caching.
Clients can reuse operation definitions and avoid costly recreation of the operation. Clients can represent operation definitions in a clear and straightforward manner. Variables make it simple to avoid mishandling of personally identifiable information (PII).
Recommended
query SurveyAnswers($questionId: QuestionAnswersInput) { questionAnswers(input: $questionId) { result { answerId answerText } }}Variables
{ questionId: 124324}Not recommended
query SurveyAnswers { questionsAnswers(input: { questionId: 124324 }) { result { questionId answerId answerText } }}Use standard error codes for common errors
To help API consumers handle errors, use standard error codes for the most common errors.
Use these common error codes.
For JVM-based languages, the graphql-exceptions library provides these common error codes in the ErrorCode enum.
| Error code | Description |
|---|---|
BAD_USER_INPUT | The input parameter value is invalid. Use this error code for input validation beyond standard GraphQL Non-Null and type checks. |
FORBIDDEN | The request includes valid authentication credentials, but they do not allow the query or mutation. This error code is the GraphQL equivalent of HTTP 403 Forbidden. When you use FORBIDDEN, avoid exposing information that could enable enumeration attacks. For details, see Testing for User Enumeration and Guessable User Account. |
INTERNAL_SERVER_ERROR | The server encounters an unexpected failure and cannot provide a response. Use this generic error only for failures that the server cannot handle. |
QUERY_TOO_COMPLEX | The query exceeds the allowed complexity for one request. |
QUERY_TOO_NESTED | The query contains too many nested levels. |
UNAUTHENTICATED | The server does not attempt the query, mutation, or field resolution because the request lacks sufficient authentication credentials. This error code is the GraphQL equivalent of HTTP 401 Unauthorized. |
Ruby on Rails clients
To ensure the use of an operation name when you invoke a mutation or query by using Ruby on Rails, store the query in a constant.
For example, if you invoke a mutation as follows:
<OperationName>{ variables....} The operation does not necessarily appear with the <OperationName> name on Apollo Studio.
Internally, the library stores the mutation in a Ruby constant. If not, it dynamically allocates a name to it, such as:
GraphQL__Client__OperationDefinition_70349176031380To ensure the use of an operation name when you invoke the mutation or query, store the query in a constant:
CreateOrUpdateTimePunchMutation = TimePunchCreation.queryThis action appends all Ruby module names and class names and generates an operation name. For example:
TimeBackend__ExportShiftBooking__CreateOrUpdateTimePunchMutation__CreateOrUpdateTimePunchSee also
For details, see Operation type and name in the GraphQL specification.