Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/objcio/tiny-networking
Tiny Networking Library
https://github.com/objcio/tiny-networking
networking swift
Last synced: 3 days ago
JSON representation
Tiny Networking Library
- Host: GitHub
- URL: https://github.com/objcio/tiny-networking
- Owner: objcio
- License: mit
- Created: 2019-06-11T11:27:17.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-09-25T09:46:16.000Z (about 2 months ago)
- Last Synced: 2024-10-30T17:15:37.309Z (16 days ago)
- Topics: networking, swift
- Language: Swift
- Homepage: http://talk.objc.io/collections/networking
- Size: 31.3 KB
- Stars: 259
- Watchers: 7
- Forks: 37
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# TinyNetworking
This package contains a tiny networking library. It provides a struct `Endpoint`, which combines a URL request and a way to parse responses for that request. Because `Endpoint` is generic over the parse result, it provides a type-safe way to use HTTP endpoints.
Here are some examples:
## A Simple Endpoint
This is an endpoint that represents a user's data (note that there are more fields in the JSON, left out for brevity):
```swift
struct User: Codable {
var name: String
var location: String?
}func userInfo(login: String) -> Endpoint {
return Endpoint(json: .get, url: URL(string: "https://api.github.com/users/\(login)")!)
}let sample = userInfo(login: "objcio")
```The code above is just a description of an endpoint, it does not load anything. `sample` is a simple struct, which you can inspect (for example, in a unit test).
Here's how you can load an endpoint. The `result` is of type `Result`.
```swift
URLSession.shared.load(endpoint) { result in
print(result)
}
```Alternatively, you can use the async/await option.
```swift
let result = try await URLSession.shared.load(endpoint)
```## Authenticated Endpoints
Here's an example of how you can have authenticated endpoints. You initialize the `Mailchimp` struct with an API key, and use that to compute an `authHeader`. You can then use the `authHeader` when you create endpoints.
```swift
struct Mailchimp {
let base = URL(string: "https://us7.api.mailchimp.com/3.0/")!
var apiKey = env.mailchimpApiKey
var authHeader: [String: String] {
["Authorization": "Basic " + "anystring:\(apiKey)".base64Encoded]
}func addContent(for episode: Episode, toCampaign campaignId: String) -> Endpoint<()> {
struct Edit: Codable {
var plain_text: String
var html: String
}
let body = Edit(plain_text: plainText(episode), html: html(episode))
let url = base.appendingPathComponent("campaigns/\(campaignId)/content")
return Endpoint<()>(json: .put, url: url, body: body, headers: authHeader)
}
}
```## Custom Parsing
The JSON encoding and decoding are added as conditional extensions on top of the Codable infrastructure. However, `Endpoint` itself is not at all tied to that. Here's the type of the parsing function:
```
var parse: (Data?, URLResponse?) -> Result
```Having `Data` as the input means that you can write our own functionality on top. For example, here's a resource that parses images:
```swift
struct ImageError: Error {}extension Endpoint where A == UIImage {
init(imageURL: URL) {
self = Endpoint(.get, url: imageURL) { data in
Result {
guard let d = data, let i = UIImage(data: d) else { throw ImageError() }
return i
}
}
}
}
```You can also write extensions that do custom JSON serialization, or parse XML, or another format.
## Testing Endpoints
Because an `Endpoint` is a plain struct, it's easy to test synchronously without a network connection. For example, you can test the image endpoint like this:
```swift
XCTAssertThrows(try Endpoint(imageURL: someURL).parse(nil, nil).get())
XCTAssertThrows(try Endpoint(imageURL: someURL).parse(invalidData, nil).get())
XCTAssertNoThrow(try Endpoint(imageURL: someURL).parse(validData, nil).get())
```## Combine
Hsieh Min Che created a library that adds Combine endpoints to this library: https://github.com/Hsieh-1989/CombinedEndpoint
## More Examples
- In the [Swift Talk](https://talk.objc.io) backend, this is used to wrap [third-party services](https://github.com/objcio/swift-talk-backend/tree/master/Sources/SwiftTalkServerLib/ThirdPartyServices).
## More Documentation
The design and implementation of this library is covered extensively on [Swift Talk](http://talk.objc.io/). There's a collection with all the relevant episodes:
**[Networking](https://talk.objc.io/collections/networking)**
[](https://talk.objc.io/collections/networking)