GraphQL Basics
What is GraphQL?
GraphQL is a query language for APIs that lets clients request exactly the data they need. Unlike REST, where the server defines response shapes, GraphQL clients specify the fields they want.
Schema Definition
GraphQL uses a strongly-typed schema:
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
body: String!
author: User!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
}
type Mutation {
createUser(name: String!, email: String!): User!
updateUser(id: ID!, name: String): User!
deleteUser(id: ID!): Boolean!
}
Queries
Clients request specific fields:
query GetUsers {
users {
id
name
email
}
}
This returns only the requested fields with no over-fetching.
Nested Queries and Variables
GraphQL handles relationships naturally:
query GetUserWithPosts($id: ID!) {
user(id: $id) {
name
posts {
title
body
}
}
}
Variables are passed separately from the query string as a dictionary.
Mutations
Modify data with mutations:
mutation CreateUser($name: String!, $email: String!) {
createUser(name: $name, email: $email) {
id
name
}
}
Fragments
Reuse field selections with fragments:
fragment UserFields on User {
id
name
email
}
query GetUsers {
users {
...UserFields
}
}
GraphQL vs REST
REST has fixed endpoints returning full objects. GraphQL has one endpoint where clients specify exact data needs. This eliminates over-fetching and under-fetching but adds complexity in schema design and caching.
Apollo iOS
Setting Up Apollo iOS
Apollo iOS generates type-safe Swift code from your GraphQL schema.
Installation
Add Apollo to your SPM dependencies:
dependencies: [
.package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.0.0")
]
Schema Download
Download your schema:
apollo-cli download-schema https://your-api.com/graphql --output schema.graphqls
Code Generation
Create an Apollo code generation config:
# apollo-codegen-config.yml
schema: schema.graphqls
sources:
- schema: schema.graphqls
sources:
- graphql
output:
module:
type: swiftPackageManager
target: GraphQLAPI
path: ./Sources/GraphQLAPI
Run code generation:
apollo-cli generate apollo-codegen-config.yml
Creating a Client
import Apollo
import ApolloHTTP
let httpTransport = HTTPTransport(url: URL(string: "https://your-api.com/graphql")!)
let client = ApolloClient(transport: httpTransport)
Fetching Data
Use the generated query types:
let query = GetUsersQuery()
client.fetch(query: query) { result in
switch result {
case .success(let graphQLResult):
if let users = graphQLResult.data?.users {
// Use typed user data
}
case .failure(let error):
print("Error: \(error)")
}
}
// Async/await
let result = try await client.fetch(query: query)
With Authorization
Add headers for authenticated requests:
let transport = HTTPTransport(url: url)
transport.additionalHeaders = [
"Authorization": "Bearer \(token)"
]
Queries and Mutations
Writing Queries
Define queries in .graphql files and let Apollo generate types:
query GetUserProfile($id: ID!) {
user(id: $id) {
id
name
email
avatarURL
posts {
edges {
node {
id
title
createdAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
Writing Mutations
mutation CreatePost($title: String!, $body: String!) {
createPost(title: $title, body: $body) {
id
title
body
createdAt
}
}
Handling Results
Access generated types with full type safety:
let query = GetUserProfileQuery(id: "42")
client.fetch(query: query) { result in
guard let data = try? result.get().data else { return }
let name = data.user?.name
let posts = data.user?.posts?.edges?.compactMap { $0?.node } ?? []
}
Pagination
Implement cursor-based pagination:
class UserListViewModel: ObservableObject {
@Published var users: [GetUsersQuery.Data.Users.Edge.Node] = []
private var cursor: String?
private var hasNextPage = true
func loadMore() async {
guard hasNextPage else { return }
let query = GetUsersQuery(first: 20, after: cursor)
let result = try? await client.fetch(query: query)
if let data = result?.data {
let newEdges = data.users?.edges?.compactMap { $0?.node } ?? []
users.append(contentsOf: newEdges)
cursor = data.users?.pageInfo?.endCursor
hasNextPage = data.users?.pageInfo?.hasNextPage ?? false
}
}
}
Cache Policies
Apollo provides built-in caching:
let client = ApolloClient(
cache: InMemoryCache(),
transport: HTTPTransport(url: url)
)
// Return cache data, fetch if needed
client.fetch(query: query, cachePolicy: .returnCacheDataElseLoad)
// Always fetch from network
client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData)
Quiz
1. What is the main advantage of GraphQL over REST?
2. What does Apollo iOS provide?
3. What is a GraphQL fragment?
4. What cache policy fetches only from cache?
Flashcards
Question
What is GraphQL?
Click to reveal answer
Answer
A query language for APIs where clients specify exactly which fields they need from the server.
Question
What is a GraphQL fragment?
Click to reveal answer
Answer
A reusable set of fields on a specific type that can be included in queries using the spread operator.
Question
How does Apollo iOS generate types?
Click to reveal answer
Answer
Apollo downloads the GraphQL schema and generates Swift types from .graphql query files.
Question
What is the difference between queries and mutations?
Click to reveal answer
Answer
Queries read data. Mutations modify data on the server and can return the modified object.
Revision Notes
Key Takeaways
- 1. GraphQL eliminates over-fetching by letting clients request exact fields
- 2. Apollo iOS generates type-safe Swift code from GraphQL schemas
- 3. Fragments enable reusable field selections across queries
- 4. Cursor-based pagination uses pageInfo for efficient data loading
- 5. Apollo cache policies control when to use cached vs fresh data
Interview Tips
- • Explain the N+1 problem in GraphQL and how DataLoader solves it
- • Discuss when to use GraphQL vs REST for a given use case
- • Know how Apollo caching works with cache policies
- • Describe fragment reuse and its benefits for code maintainability
Cheat Sheet
GraphQL: One endpoint, clients specify data shape.
Schema: Types, Query, Mutation definitions.
Fragments: Reusable field selections (...FragmentName).
Apollo iOS: Generates Swift types from schema + queries.
Pagination: Cursor-based with pageInfo (hasNextPage, endCursor).
Cache: InMemoryCache with policies like .returnCacheDataElseLoad.