A Switch Package to simplify asynchronous http calls & for easier implementation of web api bearer token logic (OAuth)
This is a Swift Package & can be easily installed within Xcode.
- Open you iOS project in Xcode
- Navigate to the package manager through the top tab by clicking File then Add Packages...
- Input the url to this GitHub repository in the search field.
- Click on download
An map of the most important classes enums & stuff from this Swift Package
Used for making post & get calls to given url.
// Main Methods
func get<T: Decodable>(_ urlAddon: String, query: [String : LosslessStringConvertible] = [:]) async -> HttpObjectResult<T>
func post<T: Decodable>(_ urlAddon: String, body: [String : Any]) async -> HttpObjectResult<T>
Recommended over Http. Used for making post & get calls to given url. Same functionality as Http but throws a detailed failure when an api request fails.
// Main Methods
func get<T: Decodable>(_ urlAddon: String, query: [String : LosslessStringConvertible] = [:]) async throws -> T
func post<T: Decodable>(_ urlAddon: String, body: [String : Any]) async throws -> T
Recommended over HttpCatchable when building large scale apps.
// Main Methods
func get<T: Decodable>(_ urlAddon: S, query: [String : LosslessStringConvertible] = [:]) async throws -> T
func post<T: Decodable>(_ urlAddon: S, body: [String : Any]) async throws -> T
Make a simple post call to https://fakeUrl.com/sign-in
bypassInvalidCertificate: true will stop iOS from complaining when the website of the baseUrl has an invalid certificate
/// 1. Importing this package
import Http
/// 2. Creating the HttpObject
var http = Http(baseUrl: "https://fakeUrl.com/", bypassInvalidCertificate: true)
// 3. Making the post request
var result = await http.post("sign-in", body:
[
"email" : "fakeEmail@icloud.com",
"password" : "fakePassword"
])
// 4. Reading what we got from the request
if result.succeeded {
print("Succeeded")
} else {
print("Failed with message" + result.message)
}
This is an example of how to make make a post call to an api method which returns something. Lets say that https://fakeUrl.com/sign-in returns the json below.
{
"firstName": "fake",
"lastName": "json"
}
class SignInResponse: Decodable {
var firstName: String
var lastName: String
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.firstName = try container.decode(String.self, forKey: .firstName)
self.lastName = try container.decode(String.self, forKey: .lastName)
}
}
The http.post method will now decode the result from "https://fakeUrl.com/sign-in" into the specified class
import Http
var http = Http(baseUrl: "https://fakeUrl.com/", bypassInvalidCertificate: true)
/// Set the type of variable result to an HttpObjectResult<T> where T is the class
/// which you want the http.post method to decode the result into
var result: HttpObjectResult<SignInResponse> = await http.post("sign-in", body:
[
"email" : "fakeEmail@icloud.com",
"password" : "fakePassword"
])
if result.succeeded {
print("Succeeded")
print("Your first name is: " + result.object.firstName )
} else {
print("Failed with message" + result.message)
}
This Swift Package does not only simplify post & get calls but does also simplify the implementation of OAuth Authentication.
The process of implementing OAuth through the Http Swift Package consists of two parts:
- Subclass either Http, HttpCatchable or HttpCatchableGeneric
- Override & implement the method accessToken() -> String?
The value returned from the accessToken() method will if not nil be added to the header of all get and post requests.
import Http
class CustomHttp: Http {
init() {
super.init(baseUrl: "https://fakeUrl.com/")
}
override func accessToken() async -> String? {
// ... logic for receiving the token
return storedAccessToken
}
}
The example below shows how the accessToken() method could be implemented with support for updating the accessToken through a refreshToken when the accessToken no longer is valid.
The implementation below consists of:
- Check if a accessToken exists
- True: Return the accessToken
- False: Try to get a new accessToken by checking for a refreshToken
import Http
class CustomHttp: Http {
init() {
super.init(baseUrl: "https://fakeUrl.com/")
}
override func accessToken() async -> String? {
if let accessToken = _tokenService.getAccessToken() {
return accessToken
}
if let refreshToken = _tokenService.getRefreshToken() {
let http = Http(baseUrl: Constants.apiUrl.appending(path: "account"))
let result: HttpObjectResult<AccountTokensResponse> = await http.post("tokens-refresh", body: ["refreshToken" : refreshToken])
if (result.succeeded) {
_tokenService.setAccessToken(result.object.accessToken, expires: result.object.accessTokenExpires)
_tokenService.setRefreshToken(result.object.refreshToken)
return result.object.accessToken
}
}
return nil
}
}
Custom keyword for the authentication access token header can be spesified if your api does not user the standard bearer.
import Http
var http = Http(baseUrl: "https://fakeUrl.com/", bypassInvalidCertificate: true, accessTokenBearerName: "custom")
/// the access token header would now instead be:
/// "custom 13kdas021cam02mas2123masd21la0qw12"