Skip to content

Commit 30d743d

Browse files
committed
Use Codable to encode request parameters and decode response body
1 parent 330c039 commit 30d743d

File tree

11 files changed

+144
-262
lines changed

11 files changed

+144
-262
lines changed

Sources/SwiftJSONRPC/Client/RPCClient.swift

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ open class RPCClient {
1414

1515
public var requestRetrier: RequestRetrier? = nil
1616

17+
public var coder = Coder()
18+
1719
// MARK: - Private Properties
1820

1921
private let requestExecutor: RequestExecutor
@@ -33,17 +35,17 @@ open class RPCClient {
3335

3436
// MARK: - Public Functions
3537

36-
open func invoke<Result>(_ invocation: Invocation<Result>) async throws -> Result {
38+
open func invoke<Params, Result>(_ invocation: Invocation<Params, Result>) async throws -> Result {
3739
// Init request
38-
let request = makeRequest(invocation: invocation)
40+
let request = try makeRequest(invocation: invocation)
3941

4042
// Perform request
41-
return try await execute(request: request, with: invocation.parser)
43+
return try await execute(request: request)
4244
}
4345

4446
// MARK: - Private Functions
4547

46-
private func makeRequest<Result>(invocation: Invocation<Result>) -> Request {
48+
private func makeRequest<Params, Result>(invocation: Invocation<Params, Result>) throws -> Request {
4749
// TODO: Support notification type calls without identifiers
4850
// Generate request identifier
4951
let identifier = requestIdGenerator.next()
@@ -52,15 +54,15 @@ open class RPCClient {
5254
return Request(
5355
id: identifier,
5456
method: invocation.method,
55-
params: invocation.params
57+
params: try coder.encode(invocation.params)
5658
)
5759
}
5860

59-
private func execute<Result>(request: Request, with parser: AnyResultParser<Result>) async throws -> Result {
60-
return try await withCheckedThrowingContinuation { continuation in
61+
private func execute<Result: InvocationResult>(request: Request) async throws -> Result {
62+
return try await withCheckedThrowingContinuation { [coder] continuation in
6163
execute(request: request) { result in
6264
do {
63-
continuation.resume(returning: try result.result(with: parser))
65+
continuation.resume(returning: try result.result(with: coder))
6466
} catch {
6567
continuation.resume(throwing: error)
6668
}
@@ -102,10 +104,10 @@ private extension RequestExecutorResult {
102104

103105
// MARK: - Functions
104106

105-
func result<Result>(with parser: AnyResultParser<Result>) throws -> Result {
107+
func result<Result: InvocationResult>(with coder: Coder) throws -> Result {
106108
switch self {
107109
case .response(let response):
108-
return try result(for: response, with: parser)
110+
return try result(for: response, with: coder)
109111
case .error(let error):
110112
throw InvocationError.applicationError(cause: error)
111113
case .cancel:
@@ -115,18 +117,18 @@ private extension RequestExecutorResult {
115117

116118
// MARK: - Private Functions
117119

118-
private func result<Result>(for response: Response, with parser: AnyResultParser<Result>) throws -> Result {
120+
private func result<Result: InvocationResult>(for response: Response, with coder: Coder) throws -> Result {
119121
switch response.body {
120122
case .success(let successBody):
121-
return try resultForSuccessBody(successBody, with: parser)
123+
return try resultForSuccessBody(successBody, with: coder)
122124
case .error(let error):
123125
throw InvocationError.rpcError(error: error)
124126
}
125127
}
126128

127-
private func resultForSuccessBody<Result>(_ body: AnyObject, with parser: AnyResultParser<Result>) throws -> Result {
129+
private func resultForSuccessBody<Result: InvocationResult>(_ body: Any, with coder: Coder) throws -> Result {
128130
do {
129-
return try parser.parse(body)
131+
return try coder.decode(Result.self, from: body)
130132
} catch {
131133
throw InvocationError.applicationError(cause: error)
132134
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Coder.swift
3+
//
4+
//
5+
// Created by Denis Kolyasev on 09.07.2022.
6+
//
7+
8+
import Foundation
9+
10+
public struct Coder {
11+
12+
// MARK: - Initialization
13+
14+
public init(paramsEncoder: JSONEncoder = JSONEncoder(),
15+
resultDecoder: JSONDecoder = JSONDecoder()) {
16+
17+
self.paramsEncoder = paramsEncoder
18+
self.resultDecoder = resultDecoder
19+
}
20+
21+
// MARK: - Properties
22+
23+
public var paramsEncoder: JSONEncoder
24+
25+
public var resultDecoder: JSONDecoder
26+
27+
// MARK: - Functions
28+
29+
func encode<Params: InvocationParams>(_ params: Params) throws -> Request.Params? {
30+
guard Params.self != VoidInvocationParams.self else {
31+
return nil
32+
}
33+
do {
34+
let data = try paramsEncoder.encode(params)
35+
return try JSONSerialization.jsonObject(with: data, options: .allowFragments)
36+
} catch {
37+
throw ParamsEncodingError(cause: error)
38+
}
39+
}
40+
41+
func decode<Result: InvocationResult>(_ type: Result.Type, from result: Response.Result) throws -> Result {
42+
guard Result.self != VoidInvocationResult.self else {
43+
return VoidInvocationResult() as! Result
44+
}
45+
do {
46+
let data = try JSONSerialization.data(withJSONObject: result, options: .fragmentsAllowed)
47+
return try resultDecoder.decode(Result.self, from: data)
48+
} catch {
49+
throw ResultDecodingError(cause: error)
50+
}
51+
}
52+
53+
// MARK: - Inner Types
54+
55+
final class ParamsEncodingError: NestedError<Error> { }
56+
final class ResultDecodingError: NestedError<Error> { }
57+
58+
}

Sources/SwiftJSONRPC/Invocation/Invocation.swift

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,25 @@
66
//
77
// ----------------------------------------------------------------------------
88

9-
public struct Invocation<Result>
10-
{
11-
// MARK: - Construction
12-
13-
init<Parser: ResultParser>(method: String, params: Params?, parser: Parser)
14-
where Parser.Result == Result
15-
{
16-
// Init instance variables
9+
public struct Invocation<Params, Result> where Params: InvocationParams, Result: InvocationResult {
10+
11+
// MARK: - Initialization
12+
13+
init(method: String, params: Params, resultType: Result.Type) {
1714
self.method = method
1815
self.params = params
19-
self.parser = AnyResultParser<Result>(parser)
2016
}
2117

22-
// MARK: - Properties
18+
// MARK: - Properties
2319

2420
public let method: String
2521

26-
public let params: Params?
27-
28-
public let parser: AnyResultParser<Result>
29-
30-
// MARK: - Inner Types
31-
32-
public typealias Params = [String: Any?]
22+
public let params: Params
3323

3424
}
3525

36-
// ----------------------------------------------------------------------------
26+
public typealias InvocationParams = Encodable
27+
public typealias InvocationResult = Decodable
28+
29+
public struct VoidInvocationParams: InvocationParams {}
30+
public struct VoidInvocationResult: InvocationResult {}

Sources/SwiftJSONRPC/RequestExecutor/Request.swift

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,32 @@ public class Request {
1414

1515
public let method: String
1616

17-
public let params: [String: Any]?
17+
public let params: Params?
1818

1919
// MARK: - Initialization
2020

21-
init(id: String? = nil, method: String, params: [String: Any?]?) {
21+
init(id: String? = nil, method: String, params: Params?) {
2222
self.id = id
2323
self.method = method
24-
self.params = params.map { Request.prepareParams($0) }
24+
self.params = params
2525
}
2626

2727
// MARK: - Functions
2828

29-
public func buildBody() -> [String: AnyObject] {
30-
var body: [String: AnyObject] = [
31-
JsonKeys.JsonRPC: RPCClient.Version as AnyObject,
32-
JsonKeys.Method: method as AnyObject,
33-
JsonKeys.Params: params as AnyObject,
29+
public func buildBody() -> [String: Any] {
30+
var body: [String: Any] = [
31+
JsonKeys.JsonRPC: RPCClient.Version,
32+
JsonKeys.Method: method
3433
]
3534

3635
if let id = id {
37-
body[JsonKeys.Id] = id as AnyObject?
36+
body[JsonKeys.Id] = id
3837
}
39-
40-
return body
41-
}
42-
43-
// MARK: - Private Functions
44-
45-
private static func prepareParams(_ params: [String: Any?]?) -> [String: Any] {
46-
var result: [String: Any] = [:]
47-
48-
// Remove 'nil' values
49-
for (key, value) in params ?? [:]
50-
{
51-
if let value = value {
52-
result[key] = value
53-
}
38+
if let params = params {
39+
body[JsonKeys.Params] = params
5440
}
5541

56-
return result
42+
return body
5743
}
5844

5945
// MARK: - Constants
@@ -69,4 +55,9 @@ public class Request {
6955
static let Data = "data"
7056
static let Id = "id"
7157
}
58+
59+
// MARK: - Inner Types
60+
61+
public typealias Params = Any
62+
7263
}

Sources/SwiftJSONRPC/RequestExecutor/Response.swift

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@
66
//
77
// ----------------------------------------------------------------------------
88

9-
public class Response
10-
{
11-
// MARK: Construction
9+
public class Response {
1210

13-
init(response: Any) throws
14-
{
11+
// MARK: - Properties
12+
13+
public let id: String
14+
15+
public let body: Body
16+
17+
// MARK: - Initialization
18+
19+
init(response: Any) throws {
1520
guard let json = (response as? [String: AnyObject]),
1621
let version = (json[JsonKeys.JsonRPC] as? String), (version == RPCClient.Version),
1722
let id = (json[JsonKeys.Id] as? String)
@@ -47,24 +52,9 @@ public class Response
4752
}
4853
}
4954

50-
// MARK: - Properties
51-
52-
public let id: String
53-
54-
public let body: Body
55-
56-
// MARK: - Inner Types
57-
58-
public enum Body
59-
{
60-
case success(result: AnyObject)
61-
case error(error: RPCError)
62-
}
63-
64-
// MARK: Constants
55+
// MARK: - Constants
6556

66-
fileprivate struct JsonKeys
67-
{
57+
private struct JsonKeys {
6858
static let JsonRPC = "jsonrpc"
6959
static let Method = "method"
7060
static let Params = "params"
@@ -76,13 +66,17 @@ public class Response
7666
static let Id = "id"
7767
}
7868

79-
}
69+
// MARK: - Inner Types
8070

81-
// ----------------------------------------------------------------------------
71+
public enum Body {
72+
case success(result: Result)
73+
case error(error: RPCError)
74+
}
75+
76+
public typealias Result = Any
8277

83-
enum ResponseError: Error
84-
{
85-
case invalidFormat
8678
}
8779

88-
// ----------------------------------------------------------------------------
80+
enum ResponseError: Error {
81+
case invalidFormat
82+
}

Sources/SwiftJSONRPC/ResultParser/Base/Parcelable.swift

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)