Skip to content

Commit bdae21e

Browse files
author
Jacob Rakidzich
committed
add convenience functions
1 parent b2a8374 commit bdae21e

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import Foundation
2+
import Combine
3+
4+
public extension HTTPEngine {
5+
6+
/// Makes a request via HTTP
7+
/// - Parameters:
8+
/// - decodableResponse: Decodable - An object that represents the response body
9+
/// - method: HTTPMethod - `.get, .put. post` etc.,
10+
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
11+
/// - header: A dictionary of HTTP Request Headers - `["Content-Type": "text", "Some Key": "Some Value"]`
12+
/// - validator: `(Int) -> Bool` - A function to validate the response code of the request. By default, makeRequest() will fail if the status code does not fall within the 200 - 299 range. To override this, pass in a function that compares the status code and returns a boolean. True == success, False == failure. Upon failure an error will be thrown that contains the HTTPURLResponse for inspection.
13+
///
14+
/// - Returns: AnyPubliser<Data, Error>
15+
///
16+
/// -- Headers
17+
///
18+
/// By default all requests have the `["Accept-Encoding": "gzip;q=1.0,compress;q=0.5"]` header included.
19+
///
20+
/// All `.post, .put, & .patch` requests also contain `["Content-Type": "application/json"]` by default.
21+
///
22+
/// These values can be overridden by including those headers as arguments when calling this function
23+
///
24+
/// -- Validation
25+
///
26+
/// By default the validation checks for a 200-299 status code and fails if the code is out of bounds
27+
/// ```swift
28+
/// // example validator
29+
/// validator: { $0 == 202 }
30+
/// ```
31+
public func makeRequestAndParseResponse<Response: Decodable>(
32+
_ decodableResponse: Response.Type,
33+
method: HTTPMethod,
34+
url: String,
35+
header: Header? = nil,
36+
validator: ResponseValidationClosure? = nil
37+
) -> AnyPublisher<Response, Error> {
38+
makeRequestAndParseResponse(decodableResponse, method: method, url: url, body: nil as Data?, header: header, validator: validator)
39+
}
40+
41+
42+
/// Makes a request via HTTP
43+
/// - Parameters:
44+
/// - decodableResponse: Decodable - An object that represents the response body
45+
/// - method: HTTPMethod - `.get, .put. post` etc.,
46+
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
47+
/// - body: Encodable?: The encodable object that represents body data to send with a request
48+
/// - header: A dictionary of HTTP Request Headers - `["Content-Type": "text", "Some Key": "Some Value"]`
49+
/// - validator: `(Int) -> Bool` - A function to validate the response code of the request. By default, makeRequest() will fail if the status code does not fall within the 200 - 299 range. To override this, pass in a function that compares the status code and returns a boolean. True == success, False == failure. Upon failure an error will be thrown that contains the HTTPURLResponse for inspection.
50+
///
51+
/// - Returns: AnyPubliser<Data, Error>
52+
///
53+
/// -- Headers
54+
///
55+
/// By default all requests have the `["Accept-Encoding": "gzip;q=1.0,compress;q=0.5"]` header included.
56+
///
57+
/// All `.post, .put, & .patch` requests also contain `["Content-Type": "application/json"]` by default.
58+
///
59+
/// These values can be overridden by including those headers as arguments when calling this function
60+
///
61+
/// -- Validation
62+
///
63+
/// By default the validation checks for a 200-299 status code and fails if the code is out of bounds
64+
/// ```swift
65+
/// // example validator
66+
/// validator: { $0 == 202 }
67+
/// ```
68+
public func makeRequestAndParseResponse<Body: Encodable, Response: Decodable>(
69+
_ decodableResponse: Response.Type,
70+
method: HTTPMethod,
71+
url: String,
72+
body: Body?,
73+
header: Header? = nil,
74+
validator: ResponseValidationClosure? = nil
75+
) -> AnyPublisher<Response, Error> {
76+
Just(body)
77+
.tryMap { $0 != nil ? try JSONEncoder().encode($0) : nil }
78+
.flatMap { self.makeRequest(method: method, url: url, body: $0, header: header, validator: validator) }
79+
.decode(type: decodableResponse.self, decoder: JSONDecoder())
80+
.eraseToAnyPublisher()
81+
}
82+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import XCTest
2+
import Foundation
3+
import OHHTTPStubs
4+
import OHHTTPStubsSwift
5+
@testable import HTTPEngine
6+
7+
final class HTTPEngineConvenienceMethodTests: XCTestCase {
8+
static var allTests = [
9+
("make request and parse response decodes into type", testMakeRequestAndParseResponseDecodesIntoType),
10+
("make request and parse response throws if Decode fails", testMakeRequestAndParseResponseThrowsIfDecodeFails),
11+
("make request and parse response Encodes and Decodes into type", testMakeRequestAndParseResponseEncodesAndDecodesIntoType),
12+
]
13+
14+
func testMakeRequestAndParseResponseDecodesIntoType() {
15+
stub(condition: isHost("google.com") && isMethodGET()) { _ in
16+
HTTPStubsResponse(jsonObject: ["key":"value"], statusCode: 200, headers: nil)
17+
}
18+
19+
HTTPEngine()
20+
.makeRequestAndParseResponse(TestResponseBody.self, method: .get, url: "https://google.com")
21+
.assertResult(test: self) {
22+
XCTAssertEqual($0.key, "value")
23+
}
24+
25+
}
26+
27+
func testMakeRequestAndParseResponseThrowsIfDecodeFails() {
28+
stub(condition: isHost("google.com") && isMethodGET()) { _ in
29+
HTTPStubsResponse(jsonObject: [:], statusCode: 200, headers: nil)
30+
}
31+
32+
HTTPEngine()
33+
.makeRequestAndParseResponse(TestResponseBody.self, method: .get, url: "https://google.com")
34+
.assertError(test: self) {
35+
XCTAssertNotNil($0)
36+
}
37+
38+
}
39+
40+
func testMakeRequestAndParseResponseEncodesAndDecodesIntoType() {
41+
HTTPEngine()
42+
.makeRequestAndParseResponse(TestResponseBody.self, method: .get, url: "https://google.com", body: TestResponseBody(key: "something"))
43+
.assertResult(test: self) {
44+
XCTAssertEqual($0.key, "value")
45+
}
46+
47+
}
48+
}
49+
50+
struct TestResponseBody: Codable {
51+
let key: String
52+
}

0 commit comments

Comments
 (0)