A type-safe JSON-RPC 2.0 library purely written in Swift

Related tags

JSON JSONRPCKit
Overview

JSONRPCKit

Build Status Carthage compatible CocoaPods

JSONRPCKit is a type-safe JSON-RPC 2.0 library purely written in Swift.

// Generating request JSON
let batchFactory = BatchFactory(version: "2.0", idGenerator: NumberIdGenerator())
let request = Subtract(minuend: 42, subtrahend: 23)
let batch = batchFactory.create(request)
batch.requestObject // ["jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1]

// Parsing response JSON
let responseObject: Any = ["jsonrpc": "2.0", "result": 19, "id": 1]
let response = try! batch.responses(from: responseObject)
response // 19 (type of response is inferred from SubtractRequest.Response)

Requirements

  • Swift 4.0 / Xcode 9.0 or later
    • If you use Swift 3.1 (Xcode 8.3), you can use 2.0.3 instead.
  • iOS 8.0 or later
  • macOS 10.9 or later
  • watchOS 2.0 or later
  • tvOS 9.0 or later
  • Linux is also supported

Basic usage

  1. Define request type
  2. Generate request JSON
  3. Parse response JSON

Defining request type

First of all, define a request type that conforms to Request.

struct Subtract: JSONRPCKit.Request {
    typealias Response = Int

    let minuend: Int
    let subtrahend: Int

    var method: String {
        return "subtract"
    }

    var parameters: Any? {
        return [minuend, subtrahend]
    }

    func response(from resultObject: Any) throws -> Response {
        if let response = resultObject as? Response {
            return response
        } else {
            throw CastError(actualValue: resultObject, expectedType: Response.self)
        }
    }
}

Generating request JSON

To generate request JSON, pass Request instances to BatchFactory instance, which has common JSON-RPC version and identifier generator. When BatchFactory instance receives request(s), it generates identifier(s) for the request(s) and request JSON by combining id, version, method and parameters.

let batchFactory = BatchFactory(version: "2.0", idGenerator: NumberIdGenerator())
let request1 = Subtract(minuend: 42, subtrahend: 23)
let request2 = Subtract(minuend: 23, subtrahend: 42)
let batch = batchFactory.create(request1, request2)

The request JSON is available in batch.requestObject. It looks like below:

[
  {
    "method" : "subtract",
    "jsonrpc" : "2.0",
    "id" : 1,
    "params" : [
      42,
      23
    ]
  },
  {
    "method" : "subtract",
    "jsonrpc" : "2.0",
    "id" : 2,
    "params" : [
      23,
      42
    ]
  }
]

Parsing response JSON

Suppose that following JSON is returned from server:

[
  {
    "result" : 19,
    "jsonrpc" : "2.0",
    "id" : 1,
    "status" : 0
  },
  {
    "result" : -19,
    "jsonrpc" : "2.0",
    "id" : 2,
    "status" : 0
  }
]

To parse response object, execute responses(from:) of Batch instance. When responses(from:) is called, Batch finds corresponding response object by comparing request id and response id. After it find the response object, it executes responses(from:) of Response to get Request.Response from the response object.

let responseObject = ...
let (response1, response2) = try! batch.responses(from: responseObject)
print(response1) // 19
print(response2) // -19

JSON-RPC over HTTP by APIKit

APIKit is a type-safe networking abstraction layer.

Defining HTTP request type

APIKit also has RequestType that represents HTTP request.

import APIKit

struct MyServiceRequest<Batch: JSONRPCKit.Batch>: APIKit.Request {
    let batch: Batch

    typealias Response = Batch.Responses

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

    var method: HTTPMethod {
        return .post
    }

    var path: String {
        return "/"
    }

    var parameters: Any? {
        return batch.requestObject
    }

    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
        return try batch.responses(from: object)
    }
}

Sending HTTP/HTTPS request

let batchFactory = BatchFactory(version: "2.0", idGenerator: NumberIdGenerator())
let request1 = Subtract(minuend: 42, subtrahend: 23)
let request2 = Subtract(minuend: 23, subtrahend: 42)
let batch = batchFactory.create(request1, request2)
let httpRequest = MyServiceRequest(batch: batch)

Session.sendRequest(httpRequest) { result in
    switch result {
    case .Success(let response1, let response2):
        print(response1.count) // CountCharactersResponse
        print(response2.count) // CountCharactersResponse

    case .Failure(let error):
        print(error)
    }
}

License

JSONRPCKit is released under the MIT License.

Comments
  • Type 'ViewController.ServiceRequest<Batch>' does not conform to protocol 'Request'

    Type 'ViewController.ServiceRequest' does not conform to protocol 'Request'

    Following the updated example I've set up a simple request:

    ` struct ServiceRequest<Batch: JSONRPCKit.Batch>: APIKit.Request { let batch: Batch

    typealias Response = Batch.Responses
    
    var baseURL: URL {
        return URL(string: "https://someapi.com")!
    }
    
    var method: HTTPMethod {
        return .post
    }
    
    var path: String {
        return "/"
    }
    
    var parameters: Any? {
        return batch.requestObject
    }
    
    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
        return try batch.responses(from: object)
    }
    

    } `

    But i keep getting the error "Type 'ViewController.ServiceRequest' does not conform to protocol 'Request'". If I click fix it just adds var method: HTTPMethod but then complains that var method: HTTPMethod { return .post } is an invalid redeclaration.

    I am importing APIKit & JSONRPCKit with no errors.

    Any idea what's wrong?

    Thanks in advance.

    opened by jaymutzafi 8
  • JSONRPCKit Pod as dependency.

    JSONRPCKit Pod as dependency.

    I'm using a JSONRPCKit as a Pod in my Framework:

    pod 'JSONRPCKit', :git=> 'https://github.com/bricklife/JSONRPCKit.git'

    But I'm not able to add it to my .podspec:

    s.dependency 'JSONRPCKit'

    When I try to validate .podspec:

    - ERROR | [iOS] unknown: Encountered an unknown error (Unable to find a specification for 'JSONRPCKit' depended upon by 'MyFramework') during validation.

    Is it possible to add JSONRPCKit to my .podspec?

    Thank you! @bricklife , @ishkawa , @SAMUKEI

    opened by ghost 5
  • Encodable/Decodable entities in Request/Response

    Encodable/Decodable entities in Request/Response

    Hi,

    I did an implementation regarding #17 on my own. The kit now supports using Encodable/Decodable entities in Requests and Responses. I also updated tests and README to reflect the changes.

    This PR has quite extensive changes to the API and it might not be simple to integrate. At least a version bump from 3.0 -> 4.0 would be needed.

    Please let me know what you think?

    opened by ollitapa 1
  • Add podspec

    Add podspec

    This PR is based on #6. In addition to works in the PR, I did:

    • Update versions for 2.0 6ae91a7
    • Remove a file that is not referenced from xcodeproj 166176f
    opened by ishkawa 0
  • Use new version of Result lib (5.0.0)

    Use new version of Result lib (5.0.0)

    Problem

    Unable to build JSONRPCKit with Xcode 12, error log:

    ➜  JSONRPCKit git:(master) swift build
    Fetching https://github.com/antitypical/Result.git
    error: because no versions of Result match the requirement 3.2.6..<4.0.0 and Result 1.0.2..<3.2.6 contains incompatible tools version, Result 1.0.2..<4.0.0 is forbidden.
    And because root depends on Result 3.2.0..<4.0.0, version solving failed.
    

    How it was tested After this update, run swift test locally:

    ➜  JSONRPCKit git:(master) ✗ swift test
    [5/5] Linking JSONRPCKitPackageTests
    Test Suite 'All tests' started at 2020-08-29 15:16:00.118
    Test Suite 'JSONRPCKitPackageTests.xctest' started at 2020-08-29 15:16:00.119
    Test Suite 'BatchElementTests' started at 2020-08-29 15:16:00.119
    Test Case '-[JSONRPCKitTests.BatchElementTests testNotificationRequestObject]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testNotificationRequestObject]' passed (0.052 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testRequestObject]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testRequestObject]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArray]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArray]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayErrorObjectParseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayErrorObjectParseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArraymissingBothResultAndError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArraymissingBothResultAndError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayResponseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayResponseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayresponseNotFound]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayresponseNotFound]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayresultObjectParseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayresultObjectParseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayunsupportedVersion]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromArrayunsupportedVersion]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObject]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObject]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectErrorObjectParseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectErrorObjectParseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectmissingBothResultAndError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectmissingBothResultAndError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectResponseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectResponseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectresponseNotFound]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectresponseNotFound]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectresultObjectParseError]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectresultObjectParseError]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectunsupportedVersion]' started.
    Test Case '-[JSONRPCKitTests.BatchElementTests testResponseFromObjectunsupportedVersion]' passed (0.000 seconds).
    Test Suite 'BatchElementTests' passed at 2020-08-29 15:16:00.176.
    	 Executed 16 tests, with 0 failures (0 unexpected) in 0.056 (0.057) seconds
    Test Suite 'BatchFactoryTests' started at 2020-08-29 15:16:00.176
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test1]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test1]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test2]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test2]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test3]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test3]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test4]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test4]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test5]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests test5]' passed (0.000 seconds).
    Test Case '-[JSONRPCKitTests.BatchFactoryTests testThreadSafety]' started.
    Test Case '-[JSONRPCKitTests.BatchFactoryTests testThreadSafety]' passed (0.065 seconds).
    Test Suite 'BatchFactoryTests' passed at 2020-08-29 15:16:00.242.
    	 Executed 6 tests, with 0 failures (0 unexpected) in 0.066 (0.066) seconds
    Test Suite 'JSONRPCKitPackageTests.xctest' passed at 2020-08-29 15:16:00.242.
    	 Executed 22 tests, with 0 failures (0 unexpected) in 0.122 (0.123) seconds
    Test Suite 'All tests' passed at 2020-08-29 15:16:00.242.
    	 Executed 22 tests, with 0 failures (0 unexpected) in 0.122 (0.124) seconds
    
    opened by freenancial 0
  • Support Xcode10, Swift4.2

    Support Xcode10, Swift4.2

    opened by fxwx23 0
  • After couple times(20 approx) getting data from JSONRPC , it stops doing that. Code didn't change

    After couple times(20 approx) getting data from JSONRPC , it stops doing that. Code didn't change

    Hello, I'm done with my app and working on it but it looks like that JSONRPC has limit for requests. I used about 20 times and it worked perfectly then just stopped pulling data from

    opened by turganbekuly 0
Releases(3.0.0)
Owner
Shinichiro Oba
Shinichiro Oba
Swift library for JSON-RPC

JSONRPC There are already a bunch of packages out there for doing JSON-RPC in Swift. This one is just very simple and makes no assumptions about the t

Chime 16 Dec 30, 2022
Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend

Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend. Using Argo

thoughtbot, inc. 3.5k Dec 20, 2022
JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.

JSEN /ˈdʒeɪsən/ JAY-sən JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift. A JSON, as defined in the EC

Roger Oba 8 Nov 22, 2022
Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top of Swift's Codable implementations.

DynamicCodableKit DynamicCodableKit helps you to implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top

SwiftyLab 15 Oct 16, 2022
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very important part of Pitaya.

John Lui 454 Oct 30, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
JASON is a faster JSON deserializer written in Swift.

JASON is a faster JSON deserializer written in Swift. JASON is the best framework we found to manage JSON at Swapcard. This is by far the fastest and

Damien 1k Oct 15, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
An extremely simple JSON helper written in Swift.

Alexander Alexander is an extremely simple JSON helper written in Swift. It brings type safety and Foundation helpers to the cumbersome task of JSON u

HODINKEE 36 Sep 15, 2022
Simple JSON Object mapping written in Swift

ObjectMapper ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
An iOS framework for creating JSON-based models. Written in Swift.

An iOS framework for creating JSON-based models. Written in Swift (because it totally rules!) Requirements iOS 8.0+ Xcode 7.3 Swift 2.2 Installation E

Oven Bits 448 Nov 8, 2022
A JSON parser with concise API written in Swift.

A JSON parser with concise API written in Swift Maps JSON attributes to different Swift types with just two methods: map and mapArrayOfObjects. The li

Evgenii Neumerzhitckii 14 Aug 13, 2018
[Deprecated] A shiny JSON parsing library in Swift :sparkles: Loved by many from 2015-2021

?? Deprecation Notice ?? Gloss has been deprecated in favor of Swift's Codable framework. The existing Gloss source is not going away, however updates

Harlan Kellaway 1.6k Nov 24, 2022
A JSON deserialization library for Swift

Mapper Mapper is a simple Swift library to convert JSON to strongly typed objects. One advantage to Mapper over some other libraries is you can have i

Lyft 1.2k Dec 29, 2022
Developed with use Swift language. As a third party library used SDWebImage. JSON parsing using URLSession with TMDB API. This app provide by the Core Data structure.

Capstone Project ?? About Developed with use Swift language. As a third party library used SDWebImage. JSON parsing using URLSession with TMDB API. Ad

Ensar Batuhan Unverdi 9 Aug 22, 2022