Keep in mind - this package is in the process of heavy development! 👨🏻💻 🚀
Overview
Swifty Networking is a simple package that supports the networking layer and provide, similar to SwiftUI’s ViewBuilder, request building pattern.
Note:The package is under heavy development. The structure of types and methods seems to be final, but over time there may be some changes resulting from the need to implement a new function. Version 0.5 is halfway to the first public stable version. Before this happens, I have to implement a few points according to the roadmap at the bottom.
How to use it?
Create service that provides relevant API.
struct ExampleService: Service {
var baseURL: URL { URL(string: "https://www.example.com")! }
}
Prepare models for data and error responses.
```swift
struct ExampleResponseModel: Codable {
let foo: String
let bar: Int
let buzz: Bool
}
struct ExampleErrorModel: Codable {
let status: Int
let message: String
}
Create session and send request. Of course, you can cancel it as you want. 😉
```swift
let session = Session()
let (result, error) = await session.send(request: ExampleRequest(bar: “buzz”))
if sometingIsWrong {
session.cancel(requests: .only(request.id))
}
And that’s it!
## Advanced usage
### Authorization
**SwiftyNetworking** provides easy to use and elastic authorization model. Assuming that most authorizations consist in obtaining a token from one request and using it in the others, this package contains a simple system that allows you to catch and use such values.
1. Create a new inheritance structure from `AuthorizationService`. There are two variables and one method that are needed to store sensitive data. The most important part is `func authorize<R: Request>(_ request: R) -> R` which is a place where you can inject token from the store.
```swift
struct BackendAuthorization: AuthorizationProvider {
var store: AuthorizationStore = BackendAuthorizationStore()
var afterAuthorization: ((Codable, AuthorizationStore) -> Void)? = nil
func authorize<R: Request>(_ request: R) -> R {
if let token = store.get(key: .token) {
return request.headers {
Authorization(.bearer(token: token))
}
} else {
return request
}
}
}
Create a new inheritance structure from AuthorizationStore. There will be a default KeychainAuthorizationStore implementation, but for now I will use a custom structure.
We are ready to catch our credentials. In this case, it will be a token that the server returns after authentication process.
```swift
struct ExampleLoginRequest: Request { var body: some Request {
Get("login", from: ExampleService())
//[...]
.responseBody(LoginResponse.self)
.afterAutorization { response, store in
store.value(.token(response.token))
}
}
4. Add `authorize()` modifier to each request that requires authorization.
```swift
struct ExampleAuthorizedRequest: Request {
var body: some Request {
Get("foo", bar, "buzz", from: ExampleService())
//[...]
.authorize()
}
}
}
And that is it!
Middleware
Working with the network layer, we very often perform repetitive actions such as adding the appropriate authorization header or want to save the effect of the request sent. SwiftyNetworking allows you to perform actions just before completing the query and just after receiving a response.
struct ExampleService: Service {
//[...]
func beforeEach<R>(_ request: R) -> R where R : Request {
request
.headers {
X_Api_Key(value: "secret_token")
}
}
func afterEach<B>(_ response: Response<B>) -> Response<B> where B : Decodable, B : Encodable {
statistics.store(response.statusCode)
}
}
Roadmap
Version 0.7: add before, after and beforeEach, afterEach modifiers to provide basic middleware support
Version 0.8: add Mock result that will be an alternative output for Request
Version 0.9: refactor, unit tests and whatever else that will be needed to be proud of this package 😇
What’s next?
There are a few more things I want to add and support::
Mocking data
// Dummy code
request
.mocked(where: { response in
switch response {
case successed:
//do something
case failed:
//do something
}
})
Get rid of associated types
// I would like to have only a modifier that will apply the final response type
struct ExampleRequest: Request {
var body: some Request {
Get("foo", "bar", from: ExampleService())
.responseBody(ExampleResponseModel.self)
.responseError(ExampleErrorModel.self)
}
}
}
SwiftyNetworking
Keep in mind - this package is in the process of heavy development! 👨🏻💻 🚀
Overview
Swifty Networking is a simple package that supports the networking layer and provide, similar to SwiftUI’s ViewBuilder, request building pattern.
Note: The package is under heavy development. The structure of types and methods seems to be final, but over time there may be some changes resulting from the need to implement a new function. Version 0.5 is halfway to the first public stable version. Before this happens, I have to implement a few points according to the roadmap at the bottom.
How to use it?
struct ExampleErrorModel: Codable { let status: Int let message: String }
session
and send request. Of course, you can cancel it as you want. 😉 ```swift let session = Session() let (result, error) = await session.send(request: ExampleRequest(bar: “buzz”))if sometingIsWrong { session.cancel(requests: .only(request.id)) }
AuthorizationStore
. There will be a defaultKeychainAuthorizationStore
implementation, but for now I will use a custom structure.var body: some Request {
And that is it!
Middleware
Working with the network layer, we very often perform repetitive actions such as adding the appropriate authorization header or want to save the effect of the request sent. SwiftyNetworking allows you to perform actions just before completing the query and just after receiving a response.
Roadmap
before
,after
andbeforeEach
,afterEach
modifiers to provide basic middleware supportMock
result that will be an alternative output forRequest
What’s next?
There are a few more things I want to add and support::
Mocking data
Get rid of associated types
Queueing requests
Supporting curl strings
More modifiers, more settings!