Make GraphQL requests in Swift
Reduce the number of network roundtrips and payload size

I am a Software Engineer working on open source and enterprise mobile SDKs for iOS and MacOS developers written in Swift. From 🇩🇪 and happily living in 🇺🇸
Search for a command to run...
Reduce the number of network roundtrips and payload size

I am a Software Engineer working on open source and enterprise mobile SDKs for iOS and MacOS developers written in Swift. From 🇩🇪 and happily living in 🇺🇸
Awesome!
WWDC26 kicked off on June 8, 2026. The information in this article reflects the information published by Apple on that date. There are 14 new frameworks. Name Description AccessoryAccess Manage

WWDC25 kicked off on June 9, 2025. The information in this article reflects the information published by Apple on that date. New Frameworks NameDescription AlarmKitSchedule prominent alarms and countdowns to help people manage their time. AVR...

WWDC25 is almost here, and I couldn’t be more excited! Whether you're attending the official events, community meetups, or just soaking in the energy around Cupertino, there’s no better time to connect, share ideas, and celebrate everything we love a...

In this blog post, I’ll share an observation and advice regarding the caching behavior of network responses by Apple’s APIs. If you are unfamiliar with caching of network responses then I recommend Apple’s article Accessing cached data that introduce...
WWDC24 kicked off on June 10, 2024. The information in this article reflects the information published by Apple on that date. New Frameworks NameDescription AccessorySetupKitUse AccessorySetupKit to discover accessories with Bluetooth or Wi-Fi...

In this blog post, I'll introduce GraphQL and explain how you can send and process network requests with a GraphQL query in Swift without third-party libraries.
GraphQL as a query language makes it easier for clients to ask for exactly what they need from an API.
This has two significant advantages:
As an example, let's imagine that a client wants to get the following information from a GitHub repository
Three network calls are necessary to retrieve the following information from the GitHub REST API:
The REST API would also return other fields not requested by the client.
Only one network call is required when using GraphQL. The requested fields are expressed through the GraphQL query.
POST https://api.github.com/graphql
{
repository(owner: "MarcoEidinger", name: "SwiftPlantUML") {
stargazerCount
nameWithOwner
name
url
releases(orderBy: {direction: ASC, field: CREATED_AT}, last: 2) {
nodes {
isDraft
isLatest
isPrerelease
createdAt
tagName
}
}
refs(
refPrefix: "refs/tags/"
last: 2
orderBy: {field: TAG_COMMIT_DATE, direction: ASC}
) {
edges {
node {
name
target {
... on Commit {
committedDate
}
... on Tag {
tagger {
date
}
}
}
}
}
}
}
}
If you want to learn more about GitHub's GrapQL API, you can download the latest version of the public schema from here. Better is to leverage the Explorer to get familiar with the query options.

Swift's Foundation framework allows you to send an HTTP POST request (to a GraphQL endpoint). Use JSONEncoder to encode the GraphQL query and attach it to the request as its httpBody.
In this blog post, I wanted to explicitly demonstrate how to handle GraphQL without any library, although I probably would use a library (or build my own). Tools like Apollo iOS can provide a strongly-typed GraphQL client, which makes the query creation and parsing of the response easy and safe. However, such libraries may not offer the latest features you might hope for, e.g. Swift Modern Concurrency.
If you want to go without any third-party library, I recommend using QuickType.io to generate a Swift model from your expected GraphQL response.

Here are the generated types for the given example.
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let gitHubGraphQLResponse = try? newJSONDecoder().decode(GitHubGraphQLResponse.self, from: jsonData)
import Foundation
// MARK: - GitHubGraphQLResponse
struct GitHubGraphQLResponse: Codable {
var data: DataClass?
}
// MARK: - DataClass
struct DataClass: Codable {
var repository: Repository?
}
// MARK: - Repository
struct Repository: Codable {
var stargazerCount: Int?
var nameWithOwner, name: String?
var url: String?
var releases: Releases?
var refs: Refs?
}
// MARK: - Refs
struct Refs: Codable {
var edges: [Edge]?
}
// MARK: - Edge
struct Edge: Codable {
var node: EdgeNode?
}
// MARK: - EdgeNode
struct EdgeNode: Codable {
var name: String?
var target: Target?
}
// MARK: - Target
struct Target: Codable {
var committedDate: Date?
let tagger: Tagger?
}
// MARK: - Tagger
struct Tagger: Codable {
let date: Date?
}
// MARK: - Releases
struct Releases: Codable {
var nodes: [NodeElement]?
}
// MARK: - NodeElement
struct NodeElement: Codable {
var isDraft, isLatest, isPrerelease: Bool?
var createdAt: Date?
var tagName: String?
}
Additionally, I like to create a helper Payload struct that can be used for any kind of GraphQL query.
struct Payload: Codable {
var variables: String = "{}"
var query: String
}
Here is a fully functional example of sending and processing a network request that queries one of my projects, SwiftPlantUML, with GraphQL.
import Foundation
func querySpecificRepositoryWithGraphQLQuery() async throws -> GitHubGraphQLResponse {
let username = "MarcoEidinger"
let pat = "ghp_y........."
let base64EncodedCredentials = "\(username):\(pat)".data(using: .utf8)!.base64EncodedString()
var request = URLRequest(url: URL(string: "https://api.github.com/graphql")!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// `Authorization` header required for GitHub GraphQL API
request.addValue("Basic \(base64EncodedCredentials)", forHTTPHeaderField: "Authorization")
let query =
"""
{
repository(owner: "MarcoEidinger", name: "SwiftPlantUML") {
stargazerCount
nameWithOwner
name
url
releases(orderBy: {direction: ASC, field: CREATED_AT}, last: 2) {
nodes {
isDraft
isLatest
isPrerelease
createdAt
tagName
}
}
refs(
refPrefix: "refs/tags/"
last: 2
orderBy: {field: TAG_COMMIT_DATE, direction: ASC}
) {
edges {
node {
name
target {
... on Commit {
committedDate
}
... on Tag {
tagger {
date
}
}
}
}
}
}
}
}
"""
let payload = Payload(query: query)
let postData = try! JSONEncoder().encode(payload)
request.httpBody = postData
let response = try await URLSession.shared.data(for: request)
// GitHub returns dates according to the ISO 8601 standard so let's use the appropiate stragegy. Otherwise the decoding will fail and an error gets thrown
let jsonDecoder = JSONDecoder()
jsonDecoder.dateDecodingStrategy = .iso8601
let jsonData = response.0
// Decode to the generated types by quicktype.io
let gitHubGraphQLResponse = try jsonDecoder.decode(GitHubGraphQLResponse.self, from: jsonData)
return gitHubGraphQLResponse
}
Adjust the values for variables username, pat, and query for your own example. Finally, you would need to replace GitHubGraphQLResponse.self with your response type.
Note: An authenticated user is needed to use GitHub's GraphQL API. The coding example shows how to use a personal access token, but you are better off leveraging OAuth2 for productive use.