Skip to content
This repository was archived by the owner on Sep 30, 2025. It is now read-only.

Commit c406ac9

Browse files
authored
Merge pull request #204 from kmcbride/readme-update
Update README for latest release
2 parents 7ae65cc + 499f6bb commit c406ac9

File tree

1 file changed

+66
-54
lines changed

1 file changed

+66
-54
lines changed

README.md

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Coverage Status](https://codecov.io/github/spotify/SPTDataLoader/coverage.svg?branch=master)](https://codecov.io/github/spotify/SPTDataLoader?branch=master)
44
[![Documentation](https://img.shields.io/cocoapods/metrics/doc-percent/SPTDataLoader.svg)](http://cocoadocs.org/docsets/SPTDataLoader/)
55
[![License](https://img.shields.io/github/license/spotify/SPTDataLoader.svg)](LICENSE)
6-
[![CocoaPods](https://img.shields.io/cocoapods/v/SPTDataLoader.svg)](https://cocoapods.org/?q=SPTDataLoader)
6+
[![CocoaPods](https://img.shields.io/cocoapods/v/SPTDataLoader.svg)](https://cocoapods.org/pods/SPTDataLoader)
77
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
88
[![Spotify FOSS Slack](https://slackin.spotify.com/badge.svg)](https://slackin.spotify.com)
99
[![Readme Score](http://readme-score-api.herokuapp.com/score.svg?url=https://github.com/spotify/sptdataloader)](http://clayallsopp.github.io/readme-score?url=https://github.com/spotify/sptdataloader)
@@ -26,47 +26,32 @@ As for Spotify, we wanted a light networking library that we had full control ov
2626
- **The User level**, which controls the authentication of the HTTP requests.
2727
- **The View level**, which allows automatic cancellation of requests the view has made upon deallocation.
2828

29-
### Authentication :key:
29+
### Authentication
3030
The authentication in this case is abstract, allowing the creator of the SPTDataLoaderFactory to define their own semantics for token acquisition and injection. It allows for asynchronous token acquisition if the token is invalid that seamlessly integrates with the HTTP request-response pattern.
3131

32-
### Back-off policy :cop:
32+
### Back-off policy
3333
The data loader service allows rate limiting of URLs to be set explicitly or to be determined by the server using the “Retry-After” semantic. It allows back-off retrying by using a jittered exponential backoff to prevent the thundering hordes creating a request storm after a predictable exponential period has expired.
3434

35-
## Installation
36-
SPTDataLoader can be installed in a variety of ways including traditional static libraries and dynamic frameworks. As well as using either of the dependency managers CocoaPods and Carthage.
35+
## Installation :building_construction:
36+
SPTDataLoader can be installed in a variety of ways, either as a dynamic framework, a static library, or through a dependency manager such as CocoaPods or Carthage.
3737

38-
### Static Library
39-
Simply include `SPTDataLoader.xcodeproj` in your App’s Xcode project, and link your app with the library in the “Build Phases” section.
38+
### Manually
39+
#### Dynamic Framework
40+
Drag the [framework](https://github.com/spotify/SPTDataLoader/releases) into the “Frameworks, Libraries, and Embedded Content” area in the “General” section of the target.
41+
#### Static Library
42+
Drag `SPTDataLoader.xcodeproj` into your App’s Xcode project and link your app with the library in the “Build Phases” section of the target.
4043

4144
### CocoaPods
42-
We are indexed on [CocoaPods](http://cocoapods.org), which can be installed using [Ruby gems](https://rubygems.org/):
43-
```shell
44-
$ gem install cocoapods
45-
```
46-
Then simply add `SPTDataLoader` to your `Podfile`.
47-
```
48-
pod 'SPTDataLoader', '~> 1.1'
49-
```
50-
Lastly let CocoaPods do it thing by running:
51-
```shell
52-
$ pod update
45+
To integrate SPTDataLoader into your project using [CocoaPods](http://cocoapods.org), add it to your `Podfile`:
46+
```ruby
47+
pod 'SPTDataLoader', '~> 2.1'
5348
```
5449

5550
### Carthage
56-
We support [Carthage](https://github.com/Carthage/Carthage) and provide pre-built binary frameworks for all new releases. Start by making sure you have the latest version of Carthage installed, e.g. using [Homebrew](http://brew.sh/):
57-
```shell
58-
$ brew update
59-
$ brew install carthage
60-
```
61-
You will also need to add `SPTDataLoader` to your `Cartfile`:
51+
To integrate SPTDataLoader into your project using [Carthage](https://github.com/Carthage/Carthage), add it to your `Cartfile`:
52+
```ogdl
53+
github "spotify/SPTDataLoader" ~> 2.1
6254
```
63-
github "spotify/SPTDataLoader" ~> 1.1
64-
```
65-
After that is all said and done, let Carthage pull in SPTDataLoader like so:
66-
```shell
67-
$ carthage update
68-
```
69-
Next up, you need to add the framework to the Xcode project of your App. Lastly link the framework with your App and copy it to the App’s Frameworks directory under the “Build Phases”.
7055

7156
## Usage example :eyes:
7257
For an example of this framework's usage, see the demo application `SPTDataLoaderDemo` in `SPTDataLoader.xcodeproj`. Just follow the instructions in [`ClientKeys.h`](demo/ClientKeys.h).
@@ -255,36 +240,63 @@ The SPTDataLoader architecture is designed to centralise authentication around t
255240
```
256241
As you can see all we are doing here is playing with the headers. It should be noted that if you receive an authoriseRequest: call the rest of the request will not execute until you have either sent the delegate a signal telling it the request has been authorised or failed to be authorised.
257242

258-
## Background story :book:
259-
At Spotify we have begun moving to a decentralised HTTP architecture, and in doing so have had some growing pains. Initially we had a data loader that would attempt to refresh the access token whenever it became invalid, but we immediately learned this was very hard to keep track of. We needed some way of injecting this authorisation data automatically into a HTTP request that didn't require our features to do any more heavy lifting than they were currently doing.
243+
### Swift overlay
244+
Additional APIs that enhance usage within Swift applications are available through the `SPTDataLoaderSwift` library.
245+
```swift
246+
// Creating a DataLoader instance
247+
let dataLoader = dataLoaderFactory.makeDataLoader(/* optional */responseQueue: myCustomQueue)
260248

261-
Thus we came up with a way to elegantly inject tokens in a Just-in-time manner for requests that require them. We also wanted to learn from our mistakes with our proprietary protocol, and bake in back-off policies early to avoid us DDOSing our own backends with huge amounts of eronious requests.
249+
// Creating a Request instance -- all functions can be chained
250+
let request = dataLoader.request(modelURL, sourceIdentifier: "model-page")
262251

263-
### Why no block interface?
264-
We had some block interfaces on our proprietary protocol library, and what we noticed was that it was easy to miss the weakification of the variables used in the blocks, which caused view models to be held around in memory far longer than they should have been.
265-
Another problem was whether we should use one block or multiple blocks for failures/successes, and what we learned from our old API was that developers could tend to miss failure states from a single block interface (e.g. handle an NSError passed in). Good examples of are animation blocks on UIView that do not take into account the failed BOOL passed in. This makes it necessary to use multiple blocks, however we wanted a contract where the developer was guaranteed to get a callback from the data loader on any of its ending states (even if they put in a nil to the request blocks). The way we achieved this was the use of the delegate pattern.
266-
Unfortunately the block pattern is useful in a number of different scenarios, however it is far from our main use case at Spotify. To support this we would like to point out that someone can give the userInfo of a request a block and then call that block on the delegate callback if they were so inclined (we have one or two examples of this on our codebase).
267-
```objc
268-
- (void)load
269-
{
270-
UILabel *label = [self findLabel];
271-
NSURL *URL = [NSURL URLWithString:@"https://www.spotify.com"];
272-
SPTDataLoaderRequest *request = [SPTDataLoaderRequest requestWithURL:URL sourceIdentifier:@"spotify"];
273-
dispatch_block_t block = ^ {
274-
label.text = @"Loaded";
275-
};
276-
request.userInfo = @{ @"block" : block };
277-
[self.dataLoader performRequest:request];
252+
// Modifying the request properties
253+
request.modify { request in
254+
request.body = modelData
255+
request.method = .patch
256+
request.addValue("application/json", forHeader: "Accept")
278257
}
279258

280-
- (void)dataLoader:(SPTDataLoader *)dataLoader didReceiveSuccessfulResponse:(SPTDataLoaderResponse *)response
281-
{
282-
dispatch_block_t block = response.request.userInfo[@"block"];
283-
if (block) {
284-
block();
259+
// Adding a response validator
260+
request.validate { response in
261+
guard response.statusCode.rawValue == 200 else {
262+
throw ValidationError.badStatus(code: response.statusCode.rawValue)
285263
}
286264
}
265+
266+
// Adding a response serializer (and executing the request)
267+
request.responseDecodable { response in
268+
modelResultHandler(response.result)
269+
}
270+
271+
// Cancelling the request
272+
request.cancel()
287273
```
274+
You can also define serializers to handle custom data types:
275+
```swift
276+
struct ProtobufResponseSerializer<Message: SwiftProtobuf.Message>: ResponseSerializer {
277+
func serialize(response: SPTDataLoaderResponse) throws -> Message {
278+
guard response.error == nil else {
279+
throw response.error.unsafelyUnwrapped
280+
}
281+
282+
guard let data = response.body else {
283+
throw ResponseSerializationError.dataNotFound
284+
}
285+
286+
return try Message(serializedData: data)
287+
}
288+
}
289+
290+
let modelSerializer = ProtobufResponseSerializer<MyCustomModel>()
291+
request.responseSerializable(serializer: modelSerializer) { response in
292+
modelResultHandler(response.result)
293+
}
294+
```
295+
296+
## Background story :book:
297+
At Spotify we have begun moving to a decentralised HTTP architecture, and in doing so have had some growing pains. Initially we had a data loader that would attempt to refresh the access token whenever it became invalid, but we immediately learned this was very hard to keep track of. We needed some way of injecting this authorisation data automatically into a HTTP request that didn't require our features to do any more heavy lifting than they were currently doing.
298+
299+
Thus we came up with a way to elegantly inject tokens in a Just-in-time manner for requests that require them. We also wanted to learn from our mistakes with our proprietary protocol, and bake in back-off policies early to avoid us DDOSing our own backends with huge amounts of eronious requests.
288300

289301
## Documentation :books:
290302
See the [`SPTDataLoader` documentation](http://cocoadocs.org/docsets/SPTDataLoader) on [CocoaDocs.org](http://cocoadocs.org) for the full documentation.

0 commit comments

Comments
 (0)