Working with GraphQL Schema

1. Creating Schema Definition

ElementPurposeExample
schemaDeclares root operation typesschema { query: Query }
typeObject output typetype User { id: ID! }
inputArgument typeinput UserInput { ... }
enum / interface / union / scalarOther type kinds

Example: Minimal SDL

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

type Query {
  hello: String!
  user(id: ID!): User
}

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

2. Defining Root Query Type

RuleDetail
RequiredEvery schema must have a Query type
Read-onlyConventionally side-effect free, parallelizable
NamingUse noun field names: users, user(id)

Example: Query root

type Query {
  me: User
  users(first: Int = 20, after: String): UserConnection!
  product(id: ID!): Product
}

3. Defining Root Mutation Type

RuleDetail
OptionalOnly required if writes are exposed
SequentialTop-level fields execute serially (spec)
NamingVerb-noun: createUser, updatePost
PayloadReturn a payload type for extensibility

Example: Mutation with payload

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
}

type CreateUserPayload {
  user: User
  errors: [UserError!]!
}

4. Defining Root Subscription Type

RuleDetail
TransportWebSocket (graphql-ws) or SSE
Single fieldOperation must select exactly one root field
ResolverReturns AsyncIterator of events

Example: Subscription

type Subscription {
  messageAdded(channelId: ID!): Message!
}

5. Using Schema Description Strings

SyntaxUse
"single line"Short description above type/field
"""block"""Multi-line, supports markdown
Available ontypes, fields, args, enum values, directives

Example: Descriptions

"""A registered customer of the platform."""
type User {
  "Globally unique identifier"
  id: ID!
  """
  Display name. **May be null** for anonymous users.
  """
  name: String
}

6. Organizing Schema Files

StrategyWhen
Single fileSmall APIs (< 200 lines)
Per typeMedium APIs; one .graphql per domain type
Per domain moduleLarge APIs; users/, orders/ folders with schema + resolvers
FederationSchema split across services

Example: Loading multiple SDL files

import { loadFilesSync } from "@graphql-tools/load-files";
import { mergeTypeDefs } from "@graphql-tools/merge";

const typeDefs = mergeTypeDefs(
  loadFilesSync("./src/**/*.graphql")
);

7. Extending Schema Definitions

KeywordUse
extend typeAdd fields to existing object
extend interface / enum / inputAdd members
extend schemaAdd directives or root types

Example: Module extends Query

# users/schema.graphql
type Query

extend type Query {
  me: User
  user(id: ID!): User
}

8. Naming Conventions for Types

ElementConventionExample
Types/Interfaces/UnionsPascalCase, singularUser, Node
Input typesSuffix InputCreateUserInput
Payload typesSuffix PayloadLoginPayload
Connections/EdgesSuffix per Relay specUserConnection, UserEdge
EnumsPascalCase singularOrderStatus

9. Naming Conventions for Fields

ElementConventionExample
Fields/ArgscamelCasefirstName, orderBy
Booleansis/has prefixisActive, hasAccess
Listsplural nounposts, tags
MutationsverbNouncreatePost, archiveOrder
Enum valuesSCREAMING_SNAKE_CASEIN_PROGRESS

10. Using Comments in Schema

SyntaxVisibilityUse
# commentSource-only, not in introspectionImplementer notes
"description"Exposed via introspectionAPI docs for clients
Warning: Use """...""" for anything clients should see. # comments are stripped from introspection.

11. Validating Schema Design

ToolChecks
graphql-eslintNaming, deprecation, anti-patterns
GraphQL InspectorBreaking change diff vs prior schema
apollo schema checkValidates against operation traffic
graphql-schema-linterStyle, descriptions, types-have-descriptions