func callAPI<T: Codable>(endpoint: String, method: HTTPMethod, params: [String: Any]?, body: [String: Any]?) async throws -> T
This is a function that uses Swift async/await
syntax to make an API call to a specified endpoint. It takes in three parameters: the endpoint string, the HTTP method to use (GET, POST), and an optional dictionary of parameters and body to include in the API call. It also uses a generic type T that conforms to the Decodable
protocol, which means the function can return any type that can be decoded from JSON.
private func performGetRequest<T: Codable>(endpoint: String, params: [String: Any]?) async throws -> T {
let urlString = "\(baseUrl)\(endpoint)"
var urlComponents = URLComponents(string: urlString)
var queryItems = [URLQueryItem]()
if let params = params {
for (key, value) in params {
queryItems.append(URLQueryItem(name: key, value: "\(value)"))
}
urlComponents?.queryItems = queryItems
}
These lines of code construct the URL that will be used in the API call. It first combines the base URL with the specified endpoint to get the full URL string. It then creates a URLComponents
object from the URL string, which allows you to easily add query parameters. If there are any parameters passed into the function, it loops through them and adds them as query items to the URL.
guard let url = urlComponents?.url else {
throw URLError(.badURL)
}
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
This section of code uses the URLComponents
object created earlier to get the final URL for the API call. It then creates a URLRequest
object with that URL and the specified HTTP method.
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw APIError.invalidResponse
}
These lines of code use Swift async/await
syntax to make the API call using URLSession
. Checks if the response from the API is valid (status code 200-299) and throws an error if it is not.
do {
let decoder = JSONDecoder()
let object = try decoder.decode(T.self, from: data)
return object
} catch {
throw error
}
Finally, this section of code uses JSONDecoder
to decode the JSON response from the API into the specified type T. If it succeeds, it returns the decoded object. If it fails, it throws an error.
//Post
func performPostRequest(endpoint: String, body: [String: Any]?) async throws -> T {
These lines of code use Swift async/await
syntax to make the API call using URLSession
. Checks if the response from the API is valid (status code 200-299) and throws an error if it is not.
let urlString = "\(BaseURL.jsonPlaceHolder.url)\(endpoint)"
let urlComponents = URLComponents(string: urlString)
Here we construct the URL string by combining the base URL and the endpoint. We then create a URLComponents object from the URL string.
guard let url = urlComponents?.url else {
throw URLError(.badURL)
}
We try to unwrap the url property of the URLComponents object, and throw an error if it's nil.
var request = URLRequest(url: url)
request.httpMethod = HTTPMethod.post.rawValue
We create a URLRequest object from the URL, and set the HTTP method to "POST".
if let body = body {
let data = try JSONSerialization.data(withJSONObject: body, options: [])
request.httpBody = data
}
If the body parameter is not nil, we serialize the body to JSON data and set it as the request's HTTP body.
let (data, response) = try await URLSession.shared.data(for: request)
We make an asynchronous data task using URLSession.shared.data(for:), which returns a tuple containing the data and the response. The await keyword is used to wait for the response.
guard let httpResponse = response as? HTTPURLResponse else {
throw APIError.invalidResponse
}
We check whether the response is an HTTPURLResponse, and throw an error if it's not.
if !(200...299).contains(httpResponse.statusCode) {
throw APIError.invalidResponse
}
We check whether the response status code is in the 200-299 range, and throw an error if it's not.
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
The following are the sources that helped me create the API manager:
- Official Apple documentation on URLSession usage: https://developer.apple.com/documentation/foundation/urlsession
- Official Apple documentation on Generics usage in Swift: https://docs.swift.org/swift-book/LanguageGuide/Generics.html