A few days ago, I was working on my first project that involved fetching data from an external API for my app. Since this is a fundamental task in software development, I thought about writing this tutorial on how to make a simple network request using the URLSession object and maybe help someone in the future (probably myself). So, join me, and let's work together!
URLSession
URLSession is a powerful API provided by Swift for handling network tasks, such as fetching data for our app, downloading files, and uploading data and files to remote locations.
Let's use the project I mentioned as an example. We're building an app that'll show the latest Bitcoin prices in different currencies. To make it happen, we'll use the URLSession to grab the data from the CoinAPI following four simple steps:
- Step 1: Create a URL
- Step 2: Create a URLSession
- Step 3: Give URLSession a task
- Step 4: Start the task
Important
If you're not currently working on a project, you can create a playground blank file in Xcode to follow along with this tutorial. Just make sure you import the Foundation framework.
Setting Up
Step 1: Create a URL
The URL structure identifies the location of the resource we want to access. When creating an instance of this structure, you'll notice that the same method can be called with different parameters. In our case, we'll initialize it using only the string param.
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
}
- Because URL() has an optional type, we use the optional binding concept with the if let statement to safely unwrap and access the value returned from the URL instance
Step 2: Create a URLSession
In the next step we create and configure a session for our network request.
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
}
There are three types of URL sessions that we can use:
- Default: used for basic requests and suitable for most common use cases
- Ephemeral: similar to the default config, but it doesn't store any data. For example, you can use this config when requesting user credentials for your app
- Background: allows you to download or upload data in the background, like when you suspend an app on your iOS device
Making GET Request
Step 3: Give URLSession a task
Now that we have our URLSession set up and ready to go, it's time to assign a task to it. URLSession supports three key types of tasks:
- Data tasks: send and receive data; intended for short, often interactive requests
- Download tasks: for scenarios where you want to download large files, and save them to the device's storage
- Upload tasks: typically used in scenarios like sending user-generated content or files to a server
These are the most commonly used tasks. We also have WebSocket and Stream tasks, but they're used in more advanced scenarios, so for now, I won't talk about them.
Implementing a data task for our session:
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
}
}
- We use the dataTask(with: URL, completionHandler:) method, implementing the completionHandler: function with a closure
Step 4: Start the task
The task we added to our session initially has a suspended state, which means that it's waiting for us to start it. We do this by calling its resume() method.
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
}
task.resume()
}
And, once we've done starting the task, we're able to continue and handle the response.
Handling response
When we print the data returned from the dataTask() method, it won't be possible for us to see its content.
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
// data has an optional type: Data?
// again, we use optional binding to unwrap it
if let safeData = data {
print("raw data: ", safeData)
// raw data: 138 bytes
}
}
task.resume()
}
Although we know the data is in JSON format (based on our API's documentation), that's not exactly what we got. So, what should we do?
Parsing data in JSON format
To fix this, we need to parse the data and turn it into an actual Swift object with properties and methods.
Create a Struct with the expected JSON properties
struct CoinData: Decodable {
let rate: Double
let asset_id_quote: String
}
- We use the Decodable protocol to let Swift know that our struct can decode itself from an external representation. This means that we can easily read data in JSON format and convert it into our Swift struct
Parse JSON with the native JSONDecoder
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if let safeData = data {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(
CoinData.self, // reference the type object
from: safeData
)
} catch {
print(error)
}
}
}
task.resume()
}
- The decode method (12) can throw an error, so we need to add the try word
- Because we're using the try word, we need to wrap it inside a do block
- Then, we add the catch block to handle any potential errors properly
Access properties from API JSON response
Now, if we try to access the decodedData constant, we'll be able to get the rate and asset_id_quote properties we extracted from the API JSON response.
let urlString =
"https://rest.coinapi.io/v1/exchangerate/BTC/BRL?apikey=YOUR-API-KEY"
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if let safeData = data {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(
CoinData.self, // reference the type object
from: safeData
)
print(decodedData)
// CoinData(
// rate: 140113.1208321098,
// asset_id_quote: "BRL"
// )
} catch {
print(error)
}
}
}
task.resume()
}
Conclusion
And that's it! You've successfully completed your first network request. Congratulations! As a next step, I encourage you to read Apple's documentation and learn more about the subject. I've provided you with a lot of links, so have at it.
If you have any questions, please feel free to reach out to me on Twitter or Linkedin. Thank you very much for joining me. Great work, and see you next time! 🙋🏻♂️