Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .codebeatignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sources/HTTPEngine/HTTPEngine+ConvenienceMethods.swift
1 change: 1 addition & 0 deletions Sources/HTTPEngine/Errors.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// swiftlint:disable nesting
import Foundation

public struct Errors {
Expand Down
91 changes: 86 additions & 5 deletions Sources/HTTPEngine/HTTPEngine+ConvenienceMethods.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// swiftlint:disable line_length
import Foundation
import Combine

Expand Down Expand Up @@ -81,8 +82,8 @@ public extension HTTPEngine {
.decode(type: decodableResponse.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}


/// Makes a request via HTTP and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
Expand All @@ -108,7 +109,7 @@ public extension HTTPEngine {
}


/// Makes a request via HTTP, Encodes the body and Decodes the response
/// Makes a POST request via HTTP, Encodes the body and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
Expand All @@ -134,8 +135,8 @@ public extension HTTPEngine {
makeRequestAndParseResponse(value.self, method: .post, url: url, body: body, validator: validator)
}

/// Makes a request via HTTP, Encodes the body and Decodes the response

/// Makes a POST request via HTTP, Encodes the body and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
Expand All @@ -158,6 +159,86 @@ public extension HTTPEngine {
) -> AnyPublisher<Response, Error> {
post(value.self, url: url, body: nil as NilBody?, validator: validator)
}


/// Makes a PATCH request via HTTP, Encodes the body and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
/// - body: Encodable?: The encodable object that represents body data to send with a request
/// - 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.
///
/// - Returns: AnyPubliser<Data, Error>
///
/// -- Validation
///
/// By default the validation checks for a 200-299 status code and fails if the code is out of bounds
/// ```swift
/// // example validator
/// validator: { $0 == 202 }
/// // Failure throws Errors.Response.unexpectedStatusCode(HTTPURLRequest)
/// ```
func patch<Response: Decodable, Body: Encodable>(
_ value: Response.Type,
url: String,
body: Body? = nil,
validator: ResponseValidationClosure? = nil
) -> AnyPublisher<Response, Error> {
makeRequestAndParseResponse(value.self, method: .patch, url: url, body: body, validator: validator)
}


/// Makes a PUT request via HTTP, Encodes the body and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
/// - body: Encodable?: The encodable object that represents body data to send with a request
/// - 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.
///
/// - Returns: AnyPubliser<Data, Error>
///
/// -- Validation
///
/// By default the validation checks for a 200-299 status code and fails if the code is out of bounds
/// ```swift
/// // example validator
/// validator: { $0 == 202 }
/// // Failure throws Errors.Response.unexpectedStatusCode(HTTPURLRequest)
/// ```
func put<Response: Decodable, Body: Encodable>(
_ value: Response.Type,
url: String,
body: Body? = nil,
validator: ResponseValidationClosure? = nil
) -> AnyPublisher<Response, Error> {
makeRequestAndParseResponse(value.self, method: .put, url: url, body: body, validator: validator)
}

/// Makes a DELETE request via HTTP, Encodes the body and Decodes the response
/// - Parameters:
/// - decodableResponse: Decodable - An object that represents the response body
/// - urlString: URL domain + path as a string: `"abc.com/some/path"`
/// - body: Encodable?: The encodable object that represents body data to send with a request
/// - 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.
///
/// - Returns: AnyPubliser<Data, Error>
///
/// -- Validation
///
/// By default the validation checks for a 200-299 status code and fails if the code is out of bounds
/// ```swift
/// // example validator
/// validator: { $0 == 202 }
/// // Failure throws Errors.Response.unexpectedStatusCode(HTTPURLRequest)
/// ```
func delete<Response: Decodable, Body: Encodable>(
_ value: Response.Type,
url: String,
body: Body? = nil,
validator: ResponseValidationClosure? = nil
) -> AnyPublisher<Response, Error> {
makeRequestAndParseResponse(value.self, method: .delete, url: url, body: body, validator: validator)
}
}

private struct NilBody: Encodable {}
1 change: 1 addition & 0 deletions Sources/HTTPEngine/HTTPEngine.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// swiftlint:disable line_length
import Foundation
import Combine

Expand Down
1 change: 1 addition & 0 deletions Sources/HTTPEngine/Utilities.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// swiftlint:disable line_length
import Foundation
import Combine

Expand Down
51 changes: 40 additions & 11 deletions Tests/HTTPEngineTests/HTTPEngine+ConvenieceMethodTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@ import OHHTTPStubsSwift
@testable import HTTPEngine

final class HTTPEngineConvenienceMethodTests: XCTestCase {
static var allTests = [
("make request and parse response decodes into type", testMakeRequestAndParseResponseDecodesIntoType),
("make request and parse response throws if Decode fails", testMakeRequestAndParseResponseThrowsIfDecodeFails),
("make request and parse response Encodes and Decodes into type", testMakeRequestAndParseResponseEncodesAndDecodesIntoType),
("get succeeds", testGetSucceeds),
("post succeeds", testPostSucceeds),
]


func testMakeRequestAndParseResponseDecodesIntoType() {
stub(condition: isHost("google.com") && isMethodGET()) { _ in
HTTPStubsResponse(jsonObject: ["key":"value"], statusCode: 200, headers: nil)
Expand All @@ -25,7 +18,7 @@ final class HTTPEngineConvenienceMethodTests: XCTestCase {
}

}

func testMakeRequestAndParseResponseThrowsIfDecodeFails() {
stub(condition: isHost("google.com") && isMethodGET()) { _ in
HTTPStubsResponse(jsonObject: [:], statusCode: 200, headers: nil)
Expand All @@ -46,7 +39,7 @@ final class HTTPEngineConvenienceMethodTests: XCTestCase {
XCTAssertEqual($0.key, "value")
}
}

func testGetSucceeds() {
stub(condition: isHost("google.com") && isMethodGET()) { _ in
HTTPStubsResponse(jsonObject: ["key": "value"], statusCode: 200, headers: nil)
Expand All @@ -59,7 +52,7 @@ final class HTTPEngineConvenienceMethodTests: XCTestCase {

}
}

func testPostSucceeds() {
stub(condition: isHost("google.com") && isMethodPOST()) { _ in
HTTPStubsResponse(jsonObject: ["key": "value"], statusCode: 200, headers: nil)
Expand All @@ -71,6 +64,42 @@ final class HTTPEngineConvenienceMethodTests: XCTestCase {
XCTAssertEqual($0.key, "value")
}
}

func testPatchSucceeds() {
stub(condition: isHost("google.com") && isMethodPATCH()) { _ in
HTTPStubsResponse(jsonObject: ["key": "value"], statusCode: 200, headers: nil)
}

HTTPEngine()
.patch(TestResponseBody.self, url: "https://google.com", body: nil as TestResponseBody?)
.assertResult(test: self) {
XCTAssertEqual($0.key, "value")
}
}

func testPutSucceeds() {
stub(condition: isHost("google.com") && isMethodPUT()) { _ in
HTTPStubsResponse(jsonObject: ["key": "value"], statusCode: 200, headers: nil)
}

HTTPEngine()
.put(TestResponseBody.self, url: "https://google.com", body: nil as TestResponseBody?)
.assertResult(test: self) {
XCTAssertEqual($0.key, "value")
}
}

func testDeleteSucceeds() {
stub(condition: isHost("google.com") && isMethodDELETE()) { _ in
HTTPStubsResponse(jsonObject: ["key": "value"], statusCode: 200, headers: nil)
}

HTTPEngine()
.delete(TestResponseBody.self, url: "https://google.com", body: nil as TestResponseBody?)
.assertResult(test: self) {
XCTAssertEqual($0.key, "value")
}
}
}

struct TestResponseBody: Codable {
Expand Down