Make HTTP API calls easier. Built on top of URLSession.
Use Swift Package Manager to install the library:
dependencies: [
.package(url: "https://github.com/pjechris/SimpleHTTP", from: "0.4.0"),
]
The package come with 2 modules:
SimpleHTTP
which bring the full framework API described in this READMESimpleHTTPFoundation
which only bring a few addition to Foundation API. See this article or API doc to have a glimpse of what is provided.
You make requests by creating Request
objects. You can either create them manually or provide static definition by extending Request
:
extension Request {
static let func login(_ body: UserBody) -> Request<UserResponse> {
.post("login", body: body)
}
}
This defines a Request.login(_:)
method which create a request targeting "login" path by sending a UserBody
and expecting a UserResponse
as response.
You can use your request along URLSession
by converting it into a URLRequest
by calling request.toURLRequest(encoder:relativeTo:accepting)
.
You can also use a Session
object. Session
is somewhat similar to URLSession
but providing additional functionalities:
- encoder/decoder for all requests
- error handling
- ability to intercept requests
let session = Session(
baseURL: URL(string: "https://github.com")!,
encoder: JSONEncoder(),
decoder: JSONDecoder()
)
try await session.response(for: .login(UserBody(username: "pjechris", password: "MyPassword")))
A few words about Session:
baseURL
will be prepended to all call paths- You can skip encoder and decoder if you use JSON
- You can provide a custom
URLSession
instance if ever needed
Request support two body types:
To send an Encodable object just set it as your Request body:
struct UserBody: Encodable {}
extension Request {
static func login(_ body: UserBody) -> Request<LoginResponse> {
.post("login", body: body)
}
}
You can create multipart content from two kind of content
- From a disk file (using a
URL
) - From raw content (using
Data
)
First example show how to create a request sending an audio file as request body:
extension Request {
static func send(audioFile: URL) throws -> Request<SendAudioResponse> {
var multipart = MultipartFormData()
try multipart.add(url: audioFile, name: "define_your_name")
return .post("v1/sendAudio", body: multipart)
}
}
Second example show same request but this time audio file is just some raw unknown data:
static func send(audioFile: Data) throws -> Request<SendAudioResponse> {
var multipart = MultipartFormData()
try multipart.add(data: audioFile, name: "your_name", mimeType: "audioFile_mimeType")
return .post("v1/sendAudio", body: multipart)
}
}
Note you can add multiple contents inside a MultipartFormData
. For instance here we send both a audio file and an image:
extension Request {
static func send(audio: URL, image: Data) throws -> Request<SendAudioImageResponse> {
var multipart = MultipartFormData()
try multipart.add(url: audio, name: "define_your_name")
try multipart.add(data: image, name: "your_name", mimeType: "image_mimeType")
return .post("v1/send", body: multipart)
}
}
You can declare constant paths if needed (refer to Path documentation to see more):
extension Path {
static let login: Path = "login"
}
extension Request {
static let func login(_ body: UserBody) -> Request<UserResponse> {
.post(.login, body: body)
}
}
When using Session you can add automatic behavior to your requests/responses using Interceptor
like authentication, logging, request retrying, etc...
RequestInterceptor
allows to adapt and/or retry a request:
adaptRequest
method is called before making a request allowing you to transform it adding headers, changing path, ...rescueRequestError
is called whenever the request fail. You'll have a chance to retry the request. This can be used to re-authenticate the user for instance
ResponseInterceptor
is dedicated to intercept and server responses:
adaptResponse
change the server outputreceivedResponse
notify about the server final response (a valid output or error)