Skip to content

Commit

Permalink
Merge pull request #312 from ishkawa/feature/decodable-data-parser
Browse files Browse the repository at this point in the history
Add `NonSerializedJSONDataParser` for `Foundation.Decodable`
  • Loading branch information
Econa77 authored Oct 23, 2022
2 parents b014089 + 02727ca commit 40b05b9
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 26 deletions.
8 changes: 8 additions & 0 deletions APIKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */; };
C5F9A3482903E138000CB6C4 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F9A3472903E138000CB6C4 /* Request.swift */; };
C5F9A34A2903E147000CB6C4 /* JSONRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F9A3492903E147000CB6C4 /* JSONRequest.swift */; };
C5F9A34C2905073D000CB6C4 /* NonSerializedJSONDataParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F9A34B2905073D000CB6C4 /* NonSerializedJSONDataParser.swift */; };
C5F9A34E29050A96000CB6C4 /* NonSerializedJSONDataParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F9A34D29050A96000CB6C4 /* NonSerializedJSONDataParserTests.swift */; };
C5FF1DC128A80FFD0059573D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = C5FF1DC028A80FFD0059573D /* test.json */; };
C5FF1DCF28A835600059573D /* QueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FF1DCD28A835600059573D /* QueryParameters.swift */; };
C5FF1DD028A835600059573D /* URLEncodedQueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5FF1DCE28A835600059573D /* URLEncodedQueryParameters.swift */; };
Expand Down Expand Up @@ -137,6 +139,8 @@
C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrencyTests.swift; sourceTree = "<group>"; };
C5F9A3472903E138000CB6C4 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
C5F9A3492903E147000CB6C4 /* JSONRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONRequest.swift; sourceTree = "<group>"; };
C5F9A34B2905073D000CB6C4 /* NonSerializedJSONDataParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonSerializedJSONDataParser.swift; sourceTree = "<group>"; };
C5F9A34D29050A96000CB6C4 /* NonSerializedJSONDataParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonSerializedJSONDataParserTests.swift; sourceTree = "<group>"; };
C5FF1DC028A80FFD0059573D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = "<group>"; };
C5FF1DCD28A835600059573D /* QueryParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryParameters.swift; sourceTree = "<group>"; };
C5FF1DCE28A835600059573D /* URLEncodedQueryParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLEncodedQueryParameters.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -282,6 +286,7 @@
children = (
7F698E411D9D680C00F1561D /* FormURLEncodedDataParserTests.swift */,
7F698E421D9D680C00F1561D /* JSONDataParserTests.swift */,
C5F9A34D29050A96000CB6C4 /* NonSerializedJSONDataParserTests.swift */,
ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */,
7F698E431D9D680C00F1561D /* StringDataParserTests.swift */,
);
Expand Down Expand Up @@ -373,6 +378,7 @@
7F7048E41D9D8A08003C99F6 /* DataParser.swift */,
7F7048E51D9D8A08003C99F6 /* FormURLEncodedDataParser.swift */,
7F7048E61D9D8A08003C99F6 /* JSONDataParser.swift */,
C5F9A34B2905073D000CB6C4 /* NonSerializedJSONDataParser.swift */,
ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */,
7F7048E71D9D8A08003C99F6 /* StringDataParser.swift */,
);
Expand Down Expand Up @@ -568,6 +574,7 @@
7F7048F11D9D8A12003C99F6 /* SessionTaskError.swift in Sources */,
ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */,
7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */,
C5F9A34C2905073D000CB6C4 /* NonSerializedJSONDataParser.swift in Sources */,
7F7048D71D9D89F2003C99F6 /* URLSessionAdapter.swift in Sources */,
0969AE0F259DEC6D00C498AF /* Combine.swift in Sources */,
7F7048EB1D9D8A08003C99F6 /* StringDataParser.swift in Sources */,
Expand All @@ -589,6 +596,7 @@
C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */,
7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */,
0973EE35259E2DDC00879BA2 /* CombineTests.swift in Sources */,
C5F9A34E29050A96000CB6C4 /* NonSerializedJSONDataParserTests.swift in Sources */,
C5FF1DD328A835680059573D /* URLEncodedQueryParametersTests.swift in Sources */,
7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */,
7F698E5A1D9D680C00F1561D /* URLSessionAdapterTests.swift in Sources */,
Expand Down
49 changes: 23 additions & 26 deletions Demo.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,37 @@ import APIKit
PlaygroundPage.current.needsIndefiniteExecution = true

//: Step 1: Define request protocol
protocol GitHubRequest: JSONRequest {}
protocol GitHubRequest: Request {}

extension GitHubRequest {
var baseURL: URL {
return URL(string: "https://api.github.com")!
}

var dataParser: NonSerializedJSONDataParser {
return NonSerializedJSONDataParser()
}
}

//: Step 2: Create model object
struct RateLimit {
struct RateLimit: Decodable {
let count: Int
let resetDate: Date

init?(dictionary: [String: AnyObject]) {
guard let count = dictionary["rate"]?["limit"] as? Int else {
return nil
}

guard let resetDateString = dictionary["rate"]?["reset"] as? TimeInterval else {
return nil
}
enum CodingKeys: String, CodingKey {
case rate
}
enum RateCodingKeys: String, CodingKey {
case limit
case reset
}

self.count = count
self.resetDate = Date(timeIntervalSince1970: resetDateString)
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let rateContainer = try container.nestedContainer(keyedBy: RateCodingKeys.self, forKey: .rate)
self.count = try rateContainer.decode(Int.self, forKey: .limit)
let resetTimeInterval = try rateContainer.decode(TimeInterval.self, forKey: .reset)
self.resetDate = Date(timeIntervalSince1970: resetTimeInterval)
}
}

Expand All @@ -37,21 +44,11 @@ struct RateLimit {
struct GetRateLimitRequest: GitHubRequest {
typealias Response = RateLimit

var method: HTTPMethod {
return .get
}

var path: String {
return "/rate_limit"
}

func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
guard let dictionary = object as? [String: AnyObject],
let rateLimit = RateLimit(dictionary: dictionary) else {
throw ResponseError.unexpectedObject(object)
}
let method: HTTPMethod = .get
let path: String = "/rate_limit"

return rateLimit
func response(from object: Data, urlResponse: HTTPURLResponse) throws -> Response {
return try JSONDecoder().decode(Response.self, from: object)
}
}

Expand Down
19 changes: 19 additions & 0 deletions Sources/APIKit/DataParser/NonSerializedJSONDataParser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation

/// `NonSerializedJSONDataParser` response Data data.
public class NonSerializedJSONDataParser: DataParser {
/// Returns `NonSerializedJSONDataParser`.
public init() {}

// MARK: - DataParser

/// Value for `Accept` header field of HTTP request.
public var contentType: String? {
return "application/json"
}

/// Return `Data` that expresses structure of Data response.
public func parse(data: Data) throws -> Data {
return data
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import XCTest
import APIKit
import XCTest

class NonSerializedJSONDataParserTests: XCTestCase {
func testContentType() {
let parser = NonSerializedJSONDataParser()
XCTAssertEqual(parser.contentType, "application/json")
}

func testJSONSuccess() throws {
let data = try XCTUnwrap("data".data(using: .utf8))
let parser = NonSerializedJSONDataParser()

let object = try parser.parse(data: data)
XCTAssertEqual(object, data)
}
}

0 comments on commit 40b05b9

Please sign in to comment.