Giter Club home page Giter Club logo

jsonrpckit's Introduction

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.

jsonrpckit's People

Contributors

fxwx23 avatar ishkawa avatar samukei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

jsonrpckit's Issues

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

Named parameters

Hello,

thanks for the good library! What is the best way to add named parameters?

BatchFactory question.

After code review I have question. What if I need to create Batch request that contains more than 6 commas? How should I solve this ?

Type 'ViewController.ServiceRequest<Batch>' 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.

Support for JSONDecoder

Now that Swift 4 has quite nice JSONDecoder functionality, could we support that using passing instances of Data or Decoder instead of the JSON Dictionary?

Currently the Request gets Any ( [String: Any] ) passed to

func response(from resultObject: Any) throws -> Response 

which in turn needs to be encoded to Data using

let resultData = try JSONSerialization.data(withJSONObject: resultObject, options: [])
let decoder = JSONDecoder()

return try decoder.decode(Response.self, from: resultData)

Could we skip this by passing around Data or Decoder?

like

func response(from resultObject: Data) throws -> Response 

or

func response(from decoder: Decoder) throws -> Response 

Or is this something that limits the generic use of the framework?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.