Harbor is a library for making API requests in Swift in a simple way using async/await.
- Features
- Requirements
- Installation
- Usage
- Mocks
- Contributing
- Author
- License
- Rest Requests
- JSON RPC Requests
- Auth provider handler
- Multipart Post Requests
- Retry Requests
- Cancel Request
- Debug Requests
- cURL Command Output
- Default Headers
- Custom URLSession
- mTLS Certificate
- SSL Pinning
- Swift 6 Compatible
- Mock Requests
- Swift 5.9+
- iOS 15.0
You can add Harbor to your project using CocoaPods or Swift Package Manager.
Add the following line to your Podfile:
pod 'Harbor'
Add the following to your Package.swift
file:
dependencies: [
.package(url: "https://github.com/javiermanzo/Harbor.git")
]
This provides a centralized way to manage common configuration.
You can include default headers in every request.
To configure the default headers:
await Harbor.setDefaultHeaderParameters([
"MY_CUSTOM_HEADER": "VALUE"
])
You can implement the HAuthProviderProtocol
if you need to handle authentication. Use the setAuthProvider
method of the Harbor
class to set the authentication provider.
You need to create a class that implements HAuthProviderProtocol
:
class MyAuthProvider: HAuthProviderProtocol {
func getAuthorizationHeader() async -> HAuthorizationHeader {
// Return a HAuthorizationHeader instance
}
func authFailed() async {
// This method is called when the request receives a 401 status code
}
}
After that, set your Auth provider:
await Harbor.setAuthProvider(MyAuthProvider())
If the request class has the needsAuth
property set to true
, Harbor will call the getAuthorizationHeader
method of the authentication provider to get the HAuthorizationHeader
instance to set it in the header before executing the request.
Harbor allows you to set a custom URLSession
for your requests, providing flexibility for advanced configurations such as custom caching, timeout settings, or additional protocols.
To set a custom URLSession
, use the setCustomURLSession
method:
let customSession = URLSession(configuration: .default)
await Harbor.setCustomURLSession(customSession)
Harbor supports mutual TLS (mTLS) for enhanced security in API requests. This feature allows clients to present certificates to the server, ensuring both the client and server authenticate each other.
To set up mTLS, use the setMTLS
method:
let mTLS = HmTLS(p12FileUrl: yourP12FileUrl, password: "yourPassword")
await Harbor.setMTLS(mTLS)
Harbor supports SSL Pinning to enhance the security of your API requests. SSL Pinning ensures that the client checks the server's certificate against a known pinned certificate, adding an additional layer of security.
To configure SSL Pinning, use the setSSlPinningSHA256
method:
let sslPinningSHA256 = "yourSHA256CertificateHash"
await Harbor.setSSlPinningSHA256(sslPinningSHA256)
To make a request using Harbor, you need to create a class that implements one of the following protocols.
Use the HGetRequestProtocol
protocol if you want to send a GET request.
queryParameters
: A dictionary of query parameters that will be added to the URL.Model
: The result of the request will be parsed to this entity.
Use the HPostRequestProtocol
protocol if you want to send a POST request.
bodyParameters
: A dictionary of parameters that will be included in the body of the request.bodyType
: Specifies the type of data being sent in the body of the request. It can be either json or multipart.
Use the HPatchRequestProtocol
protocol if you want to send a PATCH request.
bodyParameters
: A dictionary of parameters that will be included in the body of the request.bodyType
: Specifies the type of data being sent in the body of the request. It can be either json or multipart.
Use the HPutRequestProtocol
protocol if you want to send a PUT request.
bodyParameters
: A dictionary of parameters that will be included in the body of the request.bodyType
: Specifies the type of data being sent in the body of the request. It can be either json or multipart.
Use the HDeleteRequestProtocol
protocol if you want to send a DELETE request.
Use the HRequestWithResultProtocol
protocol if you want to parse the response into a specific model. This protocol requires you to define the type of model you expect in the response.
Model
: The result of the request will be parsed to this entity.
Once the request class is created, you can execute the request using the request
method.
Task {
let response = await MyRequestWithResult().request()
}
If you use a protocol different from HGetRequestProtocol
or HRequestWithResultProtocol
, the result of calling request()
will be an HResponse
enum.
switch response {
case .success:
break
case .cancelled:
break
case .error(let error):
break
}
If you use HGetRequestProtocol
or HRequestWithResultProtocol
, the result of calling request()
will be an HResponseWithResult
enum.
switch response {
case .success(let result):
break
case .cancelled:
break
case .error(let error):
break
}
You can cancel the task of the request if it is running. request()
will return cancelled
.
let task = Task {
let response = await MyRequestWithResult().request()
}
task.cancel()
You can print debug information about your request using the HDebugRequestProtocol
protocol. Implement the protocol in the request class.
class MyRequest: HRequestWithResultProtocol, HDebugRequestProtocol {
var debugType: HDebugRequestType = .requestAndResponse
// ...
}
debugType
defines what you want to print in the console. The options are none
, request
, response
, or requestAndResponse
.
When your request is called, you will see in the Xcode console the information about your request.
Harbor also supports JSON RPC via the HarborJRPC
package.
To use HarborJRPC, add the following import to your file:
import HarborJRPC
Use this method to set the URL for the JSON RPC requests:
HarborJRPC.setURL("https://api.example.com/")
Use this method to set the JSON RPC version:
// It uses 2.0 as default
HarborJRPC.setJRPCVersion("2.0")
Use the HJRPCRequestProtocol
protocol if you want to send a JRPC request.
Model
: The model that conforms to theCodable
protocol, representing the expected response structure.method
: A string that represents the JRPC method to be called.needsAuth
: A boolean indicating whether the request requires authentication.retries
: The number of retries in case the request fails.headers
: An optional dictionary containing any additional headers to be included in the request.parameters
: An optional dictionary of parameters to be included in the request.
To configure a request using HarborJRPC, create a struct or class that implements HJRPCRequestProtocol
. The result of calling request()
will be an HJRPCResponse
:
switch response {
case .success(let result):
break
case .cancelled:
break
case .error(let error):
break
}
Harbor allows you to register and manage mocks to facilitate testing your API requests.
Use HMock
to declare mock responses for your requests.
request
: The request type that conforms toHRequestBaseRequestProtocol
for which the mock is being set.statusCode
: The HTTP status code to return.jsonResponse
: AString
representing the JSON response. This will be decoded as the expected model for your request.error
: An optionalHRequestError
if you want to simulate an error response.delay
: An optional delay (in seconds) before returning the mock response, to simulate network latency.
To register a mock, use the register(mock:)
method. This will allow you to simulate responses instead of making actual API calls.
let mock = HMock(
///
)
await Harbor.register(mock: mock)
let jsonResponse = """
{ "name": "John Doe" }
"""
let mock = HMock(
request: MyGetUsersRequest.self,
statusCode: 200,
jsonResponse: jsonResponse
)
await Harbor.register(mock: mock)
let mock = HMock(
request: MyGetUsersRequest.self,
statusCode: 401,
error: .authNeeded
)
await Harbor.register(mock: mock)
You can configure mocks to only be used in #DEBUG, preventing them from affecting production environments. The default value is true.
await Harbor.setMocksOnlyInDebug(false)
If you need to remove a specific mock, use the remove(mock:)
method.
await Harbor.remove(mock: mock)
To clear all registered mocks, use the removeAllMocks()
method.
await Harbor.removeAllMocks()
Below is a complete example demonstrating how to set up and use mocks with Harbor:
Task {
let jsonResponse = """
{ "users": [{ "id": 1, "name": "Alice" }] }
"""
let userMock = HMock(
request: MyGetUsersRequest.self,
statusCode: 200,
jsonResponse: jsonResponse
)
// Register the mock
await Harbor.register(mock: userMock)
// Perform a request that will use the registered mock
let response = await MyGetUsersRequest().request()
switch response {
case .success(let users):
// You will receive the mocked response here
print("Users:", users)
case .error(let error):
break
case .cancelled:
break
}
}
If you run into any problems, please submit an issue. Pull requests are also welcome!
Harbor was created by Javier Manzo.
Harbor is available under the MIT license. See the LICENSE file for more info.