Fetching and parsing the JSON data returned by a URL is straightforward in Swift, thanks to the JSONDecoder
and URLSession
classes of the Foundation framework.
- This article is part of the Parsing JSON in Swift series.
FREE GUIDE: Parsing JSON in Swift - The Ultimate Cheat Sheet
Learn the fundamentals of JSON parsing in Swift, advanced decoding techniques, and tasks for app development
DOWNLOAD THE FREE GUIDETable of contents
How to fetch JSON data from an API URL in Swift
To fetch and parse JSON data from an API URL in Swift, you need to:
- Identify the URL of the resource you want to download;
- Create
Decodable
Swift types reflecting the JSON you want to parse; - Download the data using the URLSession class;
- Decode the downloaded data using the
JSONDecoder
class.
For our sample, I will use the https://gutendex.com/books/
URL from the Gutendex JSON web API to download the most popular books on Project Gutenberg.
You can open this API endpoint in your web browser and see the JSON data it returns. The data returned is extensive, but we are only interested in book titles and the number of downloads, so this is the corresponding portion of the JSON data.
{
"results": [
{
"id": 84,
"title": "Frankenstein; Or, The Modern Prometheus",
"download_count": 103323
}
]
}
Looking at this data, we need to create two nested Decodable
Swift structures that match the JSON data returned by the URL.
struct Response: Decodable {
let results: [Book]
}
struct Book: Decodable, Identifiable {
let id: Int
let title: String
let downloads: Int
enum CodingKeys: String, CodingKey {
case id, title
case downloads = "download_count"
}
}
Then, we fetch the data from the URL using the shared
instance of the URLSession
class and decode it using a JSONDecoder
instance.
func fetchBooks() async throws -> [Book] {
let url = URL(string: "https://gutendex.com/books/")!
let (data, _) = try await URLSession.shared.data(from: url)
let response = try JSONDecoder().decode(Response.self, from: data)
return response.results
}
Fetching the JSON data using a Task in SwiftUI
You can test the fetching of the JSON data in a Swift playground by calling the fetchBooks()
asynchronous function inside the body of a Task
.
Task {
let books = try await fetchBooks()
}
Inside a SwiftUI app, you fetch the JSON data and then parse it inside the task(priority:_:)
view modifier.
struct ContentView: View {
@State var books: [Book] = []
var body: some View {
List(books) { book in
LabeledContent(book.title, value: book.downloads, format: .number)
.monospacedDigit()
}
.task {
books = (try? await fetchBooks()) ?? []
}
}
func fetchBooks() async throws -> [Book] {
let url = URL(string: "https://gutendex.com/books/")!
let (data, _) = try await URLSession.shared.data(from: url)
let response = try JSONDecoder().decode(Response.self, from: data)
return response.results
}
}
After downloading, you can save the data in a JSON file. You can also pretty-print the JSON data if you need to inspect it to debug your app.
While fetching and parsing the JSON data from a single URL is pretty straightforward, an actual SwiftUI app must often download data from several API endpoints.
In that case, you should carefully architect your networking layer to interact with a REST API.
If you want a quick reference of how to parse JSON from a URL, together with other JSON parsing techniques, download my free cheat sheet below.
FREE GUIDE: Parsing JSON in Swift - The Ultimate Cheat Sheet
Learn the fundamentals of JSON parsing in Swift, advanced decoding techniques, and tasks for app development
DOWNLOAD THE FREE GUIDEMatteo has been developing apps for iOS since 2008. He has been teaching iOS development best practices to hundreds of students since 2015 and he is the developer of Vulcan, a macOS app to generate SwiftUI code. Before that he was a freelance iOS developer for small and big clients, including TomTom, Squla, Siilo, and Layar. Matteo got a master’s degree in computer science and computational logic at the University of Turin. In his spare time he dances and teaches tango.