Simple and lightweight network client which can be used by all sorts of projects.
The main components are:
NetworkClient
: The network client itself. The client is a concrete implementation of theNetworkClientProtocol
protocol.NetworkRequest
: The request definition.NetworkResponse
: The network response, containing both theURLResponse
and the decodable response.NetworkConfiguration
: The network client configuration.
The network client interface is initialized with its configuration, NetworkConfiguration
, and contains a method which performs the network request, NetworkClientProtocol.run(_:)
.
public protocol NetworkClientProtocol {
init(configuration: NetworkConfiguration)
func run<RequestModel, ResponseModel>(
_ networkRequest: NetworkRequest<RequestModel, ResponseModel>
) async throws -> NetworkResponse<ResponseModel>
}
The network request contains two types, RequestModel
and ResponseModel
. These types conform to Encodable
and Decodable
protocols, respectively.
public struct NetworkRequest<
RequestModel,
ResponseModel
> where RequestModel: Encodable, ResponseModel: Decodable
The network request can be initialized with several properties, most of them optional, used to override the network configuration when applicable. E.g., the network client might need to use a different decoder or encoder for the request, or might require additional headers.
As previously mentioned, the network request contains both the original URLResponse
and the payload decodable to ResponseModel
.
public struct NetworkResponse<ResponseModel> {
public let value: ResponseModel
public let response: URLResponse
}
The network client can be configured with default encoders and decoders, hostname, session, etc...
public final class NetworkConfiguration {
/// The session used to perform the network requests.
public let session: URLSession
/// The default JSON decoder. It can be overwritten by
/// individual requests, if necessary.
public let defaultDecoder: JSONDecoder
/// The default JSON encoder. It can be overwritten by
/// individual requests, if necessary.
public let defaultEncoder: JSONEncoder
/// The base URL component.
/// E.g., `https://hostname.com/api/v3`
public let baseURL: URL
/// The interceptor called right before performing the
/// network request. Can be used to modify the `URLRequest`
/// if necessary.
public var interceptor: ((URLRequest) -> URLRequest)?
}
Requests are built by creating NetworkRequest
instances. Below, a simple GET
requests which retrieves a list of posts bookmarked by the user. The network response is PostsResponse
, which conforms to the Decodable
protocol.
let request = NetworkRequest<VoidRequest, PostsResponse>(
path: "/posts/bookmarks",
method: .get
}
The NetworkRequest
allows custom encoders and decoders for the request, overriding the default ones from the NetworkConfiguration
.
public struct NetworkRequest<
RequestModel,
ResponseModel
> where RequestModel: Encodable, ResponseModel: Decodable {
/// The request `/path`, used in combination with the
/// `NetworkConfiguration.baseURL`.
public let path: String?
/// The HTTP request method.
public let method: HTTPMethod
/// The query URL component as an array of name/value pairs.
public let queryItems: [URLQueryItem]?
/// The data sent as the message body of a request as
/// form item as for an HTTP POST request.
public let formItems: [URLFormItem]?
/// The base URL used for the request. If present, it overrides
/// `NetworkConfiguration.baseURL`.
public let baseURL: URL?
/// The data sent as the message body of a request, such
/// as for an HTTP POST request.
public let body: RequestModel?
/// The decoder used to decode the `ResponseModel`. If not not
/// specified `NetworkConfiguration.defaultDecoder`.
/// is used instead.
public let decoder: JSONDecoder?
/// The encoder used to encode the `RequestModel`. If not not
/// specified `NetworkConfiguration.defaultEncoder`.
/// is used instead.
public let encoder: JSONEncoder?
/// A dictionary containing additional header fields
/// for the request.
public let additionalHeaders: [String: String]?
}
A network requests is performed by calling NetworkClientProtocol.run(_:)
.
// Returns NetworkRequest<VoidRequest, PostsResponse>
let bookmarksRequest = PostsAPIFactory.makeBookmarksRequest()
// Returns NetworkResponse<PostsResponse>
let bookmarksResponse = try await client.run(bookmarksRequest)
- MicroblogAPI uses MicroClient to access Micro.blog APIs. It also implements photo upload -
multipart/form-data
- using MicroClient. - MicroPinboardAPI uses MicroClient to access Pinboard's APIs.
- MicropubAPI uses MicroClient to access Micropub APIs.