-
Notifications
You must be signed in to change notification settings - Fork 125
Update readme with simple tutorial #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,148 @@ | ||
# swift-nio-http-client | ||
# SwiftNIOHTTPClient | ||
This package provides simple HTTP Client library built on top of SwiftNIO. | ||
|
||
Swift HTTP Client library built on top of SwiftNIO | ||
This library provides the following: | ||
1. Asynchronous and non-blocking request methods | ||
2. Simple follow-redirects (cookie headers are dropped) | ||
3. Streaming body download | ||
4. TLS support | ||
5. Cookie parsing (but not storage) | ||
|
||
--- | ||
|
||
**NOTE**: You will need [Xcode 10.2](https://itunes.apple.com/us/app/xcode/id497799835) or [Swift 5.0](https://swift.org/download/#swift-50) to try out `SwiftNIOHTTPClient`. | ||
|
||
--- | ||
|
||
## Getting Started | ||
|
||
#### Adding the dependency | ||
Add the following entry in your <code>Package.swift</code> to start using <code>HTTPClient</code>: | ||
|
||
```swift | ||
// it's early days here so we haven't tagged a version yet, but will soon | ||
.package(url: "https://github.com/swift-server/swift-nio-http-client.git", .branch("master")) | ||
``` | ||
and ```SwiftNIOHTTP``` dependency to your target: | ||
```swift | ||
.target(name: "MyApp", dependencies: ["NIOHTTPClient"]), | ||
``` | ||
|
||
#### Request-Response API | ||
The code snippet below illustrates how to make a simple GET request to a remote server: | ||
|
||
```swift | ||
import HTTPClient | ||
|
||
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew) | ||
httpClient.get(url: "https://swift.org").whenComplete { result in | ||
switch result { | ||
case .failure(let error): | ||
// process error | ||
case .success(let response): | ||
if let response.status == .ok { | ||
// handle response | ||
} else { | ||
// handle remote error | ||
} | ||
} | ||
} | ||
``` | ||
|
||
It is important to close client instance after use to cleanly shutdown underlying NIO ```EventLoopGroup```: | ||
``` | ||
try? httpClient.syncShutdown() | ||
``` | ||
Alternatively, you can provide shared ```EventLoopGroup```: | ||
```swift | ||
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(userProvidedGroup)) | ||
``` | ||
In this case shutdown of the client is not neccecary. | ||
|
||
## Usage guide | ||
|
||
Most common HTTP methods are supported out of the box. In case you need to have more control over the method, or you want to add headers or body, use ```HTTPRequest``` struct: | ||
```swift | ||
import HTTPClient | ||
|
||
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew) | ||
defer { | ||
try? httpClient.syncShutdown() | ||
} | ||
|
||
var request = try HTTPRequest(url: "https://swift.org", method: .POST) | ||
request.headers.add(name: "User-Agent", value: "Swift HTTPClient") | ||
request.body = .string("some-body") | ||
|
||
httpClient.execute(request: request).whenComplete { result in | ||
switch result { | ||
case .failure(let error): | ||
// process error | ||
case .success(let response): | ||
if let response.status == .ok { | ||
// handle response | ||
} else { | ||
// handle remote error | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Redirects following | ||
Enable follow-redirects behavior using the client configuration: | ||
```swift | ||
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew, | ||
configuration: HTTPClientConfiguration(followRedirects: true)) | ||
``` | ||
|
||
### Timeouts | ||
Timeouts (connect and read) can also be set using the client configuration: | ||
```swift | ||
let timeout = Timeout(connectTimeout: .seconds(1), readTimeout: .seconds(1)) | ||
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew, | ||
configuration: HTTPClientConfiguration(timeout: timeout)) | ||
``` | ||
or on per-request basis: | ||
```swift | ||
let timeout = Timeout(connectTimeout: .seconds(1), readTimeout: .seconds(1)) | ||
httpClient.execute(request: request, timeout: timeout) | ||
``` | ||
|
||
### Streaming | ||
When dealing with larger amount of data, it's critical to stream the response body instead of aggregating in-memory. Handling a response stream is done using a delegate protocol. The following example demonstrates how to count the number of bytes in a streaming response body: | ||
```swift | ||
class CountingDelegate: HTTPResponseDelegate { | ||
typealias Response = Int | ||
|
||
var count = 0 | ||
|
||
func didTransmitRequestBody() { | ||
// this is executed when request is sent, called once | ||
} | ||
|
||
func didReceiveHead(_ head: HTTPResponseHead) { | ||
// this is executed when we receive HTTP Reponse head part of the request (it contains response code and headers), called once | ||
} | ||
|
||
func didReceivePart(_ buffer: ByteBuffer) { | ||
// this is executed when we receive parts of the response body, could be called zero or more times | ||
count += buffer.readableBytes | ||
} | ||
|
||
func didFinishRequest() throws -> Int { | ||
// this is called when request is fully read, called once, this is where you return a result or throw any errors you require to propagate to the client | ||
return count | ||
} | ||
|
||
func didReceiveError(_ error: Error) { | ||
// this is called when we receive any network-related error, called once | ||
} | ||
} | ||
|
||
let request = try HTTPRequest(url: "https://swift.org") | ||
let delegate = CountingDelegate() | ||
|
||
try httpClient.execute(request: request, delegate: delegate).future.whenSuccess { count in | ||
print(count) | ||
} | ||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated to this PR but i would rename
connectTimeout
toconnect
orconnection
andreadTimeout
toread
since these are properties of aTimeout
object