Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support an RPC structure of API #664

Closed
SvyatoslavVasiliev opened this issue Apr 19, 2016 · 22 comments
Closed

Support an RPC structure of API #664

SvyatoslavVasiliev opened this issue Apr 19, 2016 · 22 comments

Comments

@SvyatoslavVasiliev
Copy link

Hi there!
I am realy sad that OpenAPI specification does not support RPC style of API, because of path centric structure. There is so many tools to describe REST API, but there is no such to describe RPC API. And recently your initiative have appeared with Open API ideology, but without supporting of RPC API style. Why? Could you add it to nearest release?

@webron
Copy link
Member

webron commented Apr 19, 2016

RPC style APIs could be a side effect of #574. An unfortunate side effect, IMHO.

@SvyatoslavVasiliev
Copy link
Author

@webron it seems like that implementation of operations really solves issue of describing RPC API. There is can be some details related to JSON RPC 2.0, for example, but I hope you cover most cases.
Thank you, and if it possible to take part in testing of your new realease, I would glad to join.

@SvyatoslavVasiliev SvyatoslavVasiliev changed the title RPC structure of API supporting Support an RPC structure of API Apr 20, 2016
@webron
Copy link
Member

webron commented Apr 20, 2016

Parent: #586.

@webron
Copy link
Member

webron commented Apr 20, 2016

Following a different thread, it's unlikely #574 will resolve it as it's controlled by the content of the request, not the structure of it. Moving it under #586.

@vearutop
Copy link
Contributor

I use swagger spec to describe JSON-RPC in a hacky way, storing method names in paths keys and ignoring non-post operations. Hack is enabled by x-service-type vendored flag.

@earth2marsh
Copy link
Member

@vearutop that sounds interesting—do you have an example you could share?

@vearutop
Copy link
Contributor

basePath is used for endpoint value.
x-service-type specifies how to treat swagger.json file.
For this vendor extension we have a patched swagger-ui which envelopes original request to something like {"jsonrpc": "2.0", "method": "getSimpleV1", "params": {"id":3}, "id": 1}.
That simple we benefit from swagger spec and tools not only for our REST, but also for JSON-RPC services.

{
  "swagger": "2.0",
  "x-service-type": "json-rpc",
  "info": {
    "title": "DummyAPI",
    "version": "master~dirty"
  },
  "host": "",
  "basePath": "/rpc",
  "schemes": [
    "http",
    "https"
  ],
  "paths": {
    "getSimpleV1": {
      "post": {
        "tags": [
          "V1"
        ],
        "summary": "Simple Get",
        "description": "Get simple by ID",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": {
              "$ref": "#/definitions/SimpleGetParameters"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "description": "request success",
            "schema": {
              "$ref": "#/definitions/Simple"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "Simple": {
      "type": "object",
      "properties": {
        "id_simple": {
          "type": "integer"
        },
        "name": {
          "type": "string"
        }
      }
    },
    "SimpleGetParameters": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer"
        }
      }
    }
  }
}

@wparad
Copy link

wparad commented May 24, 2016

That's a little disappointing, I was really hoping to see something interesting, like folding of the parameters into the existing document, with clever uses of the flags. Having to use a different library to pull meaningful data is unfortunate.

@vearutop
Copy link
Contributor

Sorry, @wparad, I did not mean to make you sad (mind hacky way disclaimer).
Not sure I got you right, by "folding of the parameters into the existing document" do you mean having JSON-RPC envelope structures built in schema definition? What is "different library"?

@SvyatoslavVasiliev
Copy link
Author

@vearutop, could you clarify, your API has structure according to JSON RPC 2.0 or you are just using RPC style for URL resources?

@vearutop
Copy link
Contributor

@SvyatoslavVasiliev, API is serving valid JSON RPC 2.0 structures.
JSON RPC enveloping (including batch requests) is done by client and server according to spec.
method, params and result is defined and validated by swagger.json path, post-parameters and post-responses-200 accordingly.
Endpoint URI is defined in swagger.json as basePath.
Service host is dynamic and loadbalanced, so it is not present in swagger.json.

Actually this swagger.json is not valid, since it does not have / at the beginning of paths keys.
But this approach made possible to achieve "compatibility" with least effort.

@SvyatoslavVasiliev
Copy link
Author

@vearutop, thank you, as I am looking for some tool to specify my JSON RPC API, I will try your approach in swagger. But unfortunately, as @wparad already said, standard swagger library won't be able to work with it fully. For example if I try to upload your specification in on-line swagger editor I won't able to make API requests, because of wrong auto generated URL.

@AlJohri
Copy link

AlJohri commented Dec 29, 2016

hi @webron, I was wondering if there's any update on this issue? thanks!

@radek-smseagle
Copy link

Hi, same here. I would really be glad to hear that OpenAPI (Swagger) can handle JSON RPC style APIs.

@dasheck0
Copy link

+1 for this. Swagger is de facto standard. It should feel the urge to influence the standard of RPC documentation as well.

@o314
Copy link

o314 commented May 6, 2017

+1000
REST = SQL Web API != Computer Science + Information Technology + Computational Science
Trying to implement google maps in sql may help to understand the most stubborn soul.

Data manipulation and, side by side, function call is a must.

By the way json-rpc 2 is pretty simple, good and stable.

@darrelmiller
Copy link
Member

OpenAPI provides JSON Schema to describe a wide range of payloads. If an API provider decides to create a single path item object with many different payloads in order to tunnel procedure calls, then OpenAPI can do that. The support for JSON Schema oneOf in OpenAPI V3 will make that even easier.

If people want to build tooling that map those payloads into UI as if they were different path item objects, then they are free to do so. I don't believe that the OpenAPI spec should try and standardize a mapping between those payloads and native HTTP constructs. If there is sufficient community support to standardize that mapping then I would encourage that community to create it and encourage tool builders to support it.

@o314
Copy link

o314 commented May 6, 2017

@darrelmiller

I have to admit it's a bit harsh to understand all the terms you cite for an outsider for now o:
(But i have a second screen diffusing the linux foundation mooc at this same amazing time, and sure, that will help to catch in the long run).

I will follow your tips and wait/contribute example from/to the community.

By the way, thanks for the quick answer, and what a good teasing for the v3!

@ltfschoen
Copy link

ltfschoen commented Nov 9, 2018

I ended up using @vearutop 's approach to create a demo. We have a single endpoint for JSON-RPC calls that each have a different method. But I've explained how we resolved it in the main "info" > "description" section of the following OAS3 that I've pushed here:
https://github.com/ltfschoen/swagger/blob/master/scon_substrate_0.4.0_swagger.json
It can be viewed with Swagger UI here: https://app.swaggerhub.com/apis-docs/scon/substrate/0.4.0
And I also imported into Readme.io here: https://substrate.readme.io/v1.0.0/reference

@thephez
Copy link

thephez commented Dec 4, 2018

I ran into this issue recently too and ended up here from swagger-api/swagger-codegen#4274. I finally have something that is working relatively well for what I am doing so I created a JSON-RPC 2.0 OAS sample gist for anyone else that may benefit from it. You can copy/paste it into http://editor.swagger.io/ to experiment with it.

There is a simple POST that includes a JSON-RPC param. I also showed how to use a ref (in conjunction with allOf) to avoid duplicating the method, id and jsonrpc properties.

Copy of gist:

{
  "x-send-defaults": true,
  "openapi": "3.0.0",
  "x-api-id": "json-rpc-example",
  "info": {
    "title": "JSON-RPC OpenAPI",
    "version": "1.0.0",
    "description": "Example of how to describe a JSON-RPC 2 API in OpenAPI"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:3000"
    }
  ],
  "paths": {
    "/examplePost": {
      "post": {
        "operationId": "examplePost",
        "deprecated": false,
        "summary": "Example of JSON-RPC2 Post",
        "description": "Example post using JSON-RPC params.",
        "tags": [
          "JSONRPC"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "method",
                  "id",
                  "jsonrpc",
                  "params"
                ],
                "properties": {
                  "method": {
                    "type": "string",
                    "default": "examplePost",
                    "description": "Method name"
                  },
                  "id": {
                    "type": "integer",
                    "default": 1,
                    "format": "int32",
                    "description": "Request ID"
                  },
                  "jsonrpc": {
                    "type": "string",
                    "default": "2.0",
                    "description": "JSON-RPC Version (2.0)"
                  },
                  "params": {
                    "title": "Parameters",
                    "type": "object",
                    "required": [
                      "jsonParam"
                    ],
                    "properties": {
                      "jsonParam": {
                        "type": "integer",
                        "default": 1,
                        "description": "A param to include"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/examplePost2": {
      "post": {
        "operationId": "examplePost2",
        "deprecated": false,
        "summary": "Example of JSON-RPC2 Post",
        "description": "Example post using JSON-RPC params. Also uses a ref to avoid duplicating properties.",
        "tags": [
          "JSONRPC"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/examplePost"
              }
            }
          }
        }
      }
    }
  },
  "x-headers": [],
  "x-explorer-enabled": true,
  "x-proxy-enabled": true,
  "x-samples-enabled": true,
  "x-samples-languages": [
    "curl",
    "node",
    "ruby",
    "javascript",
    "python"
  ],
  "components": {
    "schemas": {
      "JsonRpcRequired": {
        "type": "object",
        "required": [
          "method",
          "id",
          "jsonrpc"
        ],
        "properties": {
          "method": {
            "type": "string",
            "default": "examplePost",
            "description": "Method name"
          },
          "id": {
            "type": "integer",
            "default": 1,
            "format": "int32",
            "description": "Request ID"
          },
          "jsonrpc": {
            "type": "string",
            "default": "2.0",
            "description": "JSON-RPC Version (2.0)"
          }
        },
        "discriminator": {
          "propertyName": "method_name"
        }
      },
      "examplePost": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JsonRpcRequired"
          },
          {
            "type": "object",
            "properties": {
              "params": {
                "title": "Parameters",
                "type": "object",
                "required": [
                  "jsonParam"
                ],
                "properties": {
                  "jsonParam": {
                    "type": "integer",
                    "default": 1,
                    "description": "A param to include"
                  }
                }
              }
            }
          }
        ]
      }
    }
  },
  "tags": []
}

@CharlieBreval
Copy link

CharlieBreval commented Oct 19, 2021

@thephez Thanks a lot for your gist, very interesting and helpfull 🥇 .
One point that I don't understand is that using json-rpc, we use to always call the same url, kind of "/json-rpc", because the url doesn't matter as we are using the method name as discriminant.

Meanwhile on your example, the 2 calls you described are hitting 2 different urls

@thephez
Copy link

thephez commented Oct 19, 2021

@CharlieBreval Glad it was helpful to you. It's been a while, but as I recall I my reason for the 2 different URLs had something to do with the specific tool that I was importing this into.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests