GraphQL - Interview preparation guide
What is GraphQL?
GraphQL is a query language for APIs and a runtime for executing those queries. It allows clients to request exactly the data they need, reducing over-fetching and under-fetching issues. It was developed by Facebook in 2012 and open-sourced in 2015.
What are the core components of GraphQL?
- Schema: Defines the structure and types of data available.
- Query: Used to fetch data (equivalent to GET in REST).
- Mutation: Used to modify data (Create, Update, Delete).
- Subscription: Provides real-time updates.
- Resolver: Functions that fetch the actual data for the queries and mutations.
How is GraphQL different from REST?
Feature | GraphQL | REST |
---|---|---|
Data Fetching | Request specific fields | Fetch entire resources |
Over-fetching | No (only requested fields) | Yes (fixed endpoint data) |
Under-fetching | No (nested queries allowed) | Yes (multiple requests) |
Versioning | Not required | Requires new endpoints |
Performance | Single request for complex data | Multiple round-trips |
What is a GraphQL schema?
A GraphQL schema is a blueprint that defines the types of data and operations (queries, mutations, subscriptions) supported by the API. Example schema:
type User {
id: ID! name: String! email: String!
}
type Query {
getUser(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User
}
what is a GraphQL query?
A query is used to fetch data from the server.
Example query:
query { getUser(id: "1") { name email } }
What is a GraphQL mutation?
A mutation is used to modify data on the server (create, update, delete).
Example mutation:
mutation { createUser(name: "Alice", email: "[email protected]") { id name } }
What is a GraphQL subscription?
A subscription allows clients to receive real-time updates.
Example subscription:
subscription { userAdded { id name } }
What is a resolver in GraphQL?
Resolvers are functions that handle the logic behind GraphQL queries, mutations, and subscriptions.
Example resolver:
const resolvers = { Query: { getUser: (_, { id }) => getUserById(id), }, Mutation: { createUser: (_, { name, email }) => createUser(name, email), }, };
What are GraphQL variables and why are they useful?
Variables make queries dynamic and reusable.
Example query with variables:
query GetUser($id: ID!) { getUser(id: $id) { name email } }
Passing variables:
{ "id": "1" }
What is a GraphQL fragment?
A fragment allows you to reuse fields in multiple queries.
Example fragment:
fragment UserFields on User { id name email } query { getUser(id: "1") { ...UserFields } }
How does GraphQL handle errors?
GraphQL returns errors alongside a data
field.
Example error response:
{ "data": null, "errors": [ { "message": "User not found", "locations": [{ "line": 2, "column": 3 }], "path": ["getUser"] } ] }
What are the benefits of using GraphQL?
- Efficient Data Fetching: Clients request exactly the fields they need.
- Strongly Typed Schema: Enforces a contract between client and server.
- Single Endpoint: Access all resources through a single endpoint.
- Reduced Over-fetching/Under-fetching: Flexible queries prevent these issues.
- Real-time Updates: Via subscriptions for event-driven data.
What are the drawbacks of GraphQL?
- Complexity: More setup and learning curve than REST.
- Caching Challenges: Difficult to cache responses compared to REST.
- Performance Overhead: Parsing and resolving dynamic queries may be slower.
- Security Risks: Requires limiting query depth to avoid denial-of-service attacks.
What is introspection in GraphQL?
Introspection allows clients to query the schema itself and retrieve metadata.
Example introspection query:
`{ __schema { types { name fields { name } } } }`
What are some best practices for designing GraphQL APIs?
- Schema Design: Keep the schema simple and modular.
- Pagination: Implement cursor-based pagination for large datasets.
- Security: Limit query depth and rate-limit requests.
- Batching: Use DataLoader for optimizing N+1 query problems.
- Error Handling: Provide clear and consistent error responses.
- Caching: Use persisted queries or cache at the resolver level.
How do you implement authentication and authorization in GraphQL?
- Authentication: Use tokens (e.g., JWT) to verify users.
- Authorization: Check user roles in resolvers before returning data.
Example context for authorization:
const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { const token = req.headers.authorization || ""; const user = verifyToken(token); return { user }; }, });
What are Apollo Client and Apollo Server?
- Apollo Client: A state management library for consuming GraphQL APIs.
- Apollo Server: A GraphQL server implementation supporting queries, mutations, and subscriptions.
How do you handle pagination in GraphQL?
Implement cursor-based pagination using startCursor
, endCursor
, and hasNextPage
.
Example schema:
type UserConnection { edges: [UserEdge] pageInfo: PageInfo } type UserEdge { cursor: String node: User } type PageInfo { hasNextPage: Boolean endCursor: String }
What are some common GraphQL tools and libraries?
- Apollo Server/Client: Comprehensive GraphQL solution.
- GraphQL.js: Core reference implementation.
- GraphQL Code Generator: Generates TypeScript types from schema.
- Hasura: Auto-generates GraphQL over databases.
What is schema stitching and federation?
- Schema Stitching: Combines multiple GraphQL schemas into a single schema.
- Federation: Distributes a GraphQL schema across multiple services while presenting a unified API.