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

How to document cnd's HTTP API #38

Merged
merged 20 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions 0015-how-to-document-cnd-http-api.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
= How to document the cnd HTTP API =
Lucas Soriano del Pino <lucas@coblox.tech>;
:toc:
:revdate: 2019-08-29

NOTE: Author: {authors} +
Date: {revdate} +
Tracking issue: https://github.com/comit-network/comit-rs/issues/1122[#1122]

== Context ==

We have no documentation for cnd's HTTP API. Having it is a hard requirement if we want to cater to application developers. It should also be helpful for the team and for newcomers.
luckysori marked this conversation as resolved.
Show resolved Hide resolved
luckysori marked this conversation as resolved.
Show resolved Hide resolved

== Research ==
luckysori marked this conversation as resolved.
Show resolved Hide resolved
We have no documentation for cnd's HTTP API. Having it is a hard requirement if we want to cater to application developers. It should also be helpful for the team and for newcomers.
luckysori marked this conversation as resolved.
Show resolved Hide resolved
luckysori marked this conversation as resolved.
Show resolved Hide resolved

=== Which API specification approach should we use? ===

==== Options ====

===== https://github.com/OAI/OpenAPI-Specification[OpenAPI] =====
* Extremely popular (specification has over 15k stars on GitHub).
* https://openapi.tools/[Great tooling].
* APIs can be specified using either https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml[YAML] or JSON.
* "Winner" of API Description Wars.

===== https://github.com/raml-org/raml-spec/[RAML] =====
* Quite popular (specification has over 3k stars on GitHub).
* APIs can be specified using YAML.
* https://raml.org/projects[Lots of tooling].
* Good for designing large numbers of APIs.
* Company behind joined Open API Initiative in 2017.

===== https://github.com/apiaryio/api-blueprint/[API Blueprint] =====
* Very popular (specification has over 7k stars on GitHub).
* More accessible to newcomers to API description.
* Targets human readability over machine readability.
* https://apiblueprint.org/tools.html[Lots of tooling].
* APIs can be specified using a description language on top of Markdown (conforms to GitHub Flavored Markdown).
* Company behind joined Open API Initiative in 2016.

===== Roll our own =====
* More flexible.
* No tooling.
* An https://gist.github.com/iros/3426278[example] showing how it could look.

==== Recommendation ====
OpenAPI, because it appears to be the industry standard, and is compatible with the most tools. The better human readability of API Blueprint doesn't seem all that important given that these specifications can be viewed using powerful tools such as https://rebilly.github.io/ReDoc/[ReDoc].

=== How would a developer validate its API usage against the specification? ===
Mock servers powered by tools such as https://connexion.readthedocs.io/en/latest/[Connexion] or https://stoplight.io/prism[Prism]. These tools take a HTTP API specification and simulate a server that responds to requests according to the specification. This comes for free as long as we use one of the API description languages introduced above.

=== How do we ensure that API specification and implementation are in sync? ===

==== Options ====

===== https://inspector.swagger.io/builder[Swagger Inspector] =====
* Online tool.
* Quick, manual testing.
* Can generate OpenAPI specifications from requests and responses.

===== https://dredd.org/en/latest/index.html[Dredd] =====
* Language-agnostic.
* Works with both OpenAPI and API Blueprint.
* Very popular (over 3k stars on GitHub).
* Command line tool.
* Takes API specification and makes requests to server based on that, reporting whether the responses match the documentation.
* Example:
[source,sh]
----
dredd cnd-http-api-description.yml http://localhost:<port-where-cnd-is-hosted>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the API documentation would be enough for dredd to generate random-yet-valid queries. That's cool.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. But since you mention the word "random", it's important to point out that this is not fuzz-testing.

----
* Can run code before/after specific tests by using https://dredd.readthedocs.io/en/latest/hooks/[hooks] (https://dredd.org/en/latest/hooks/rust.html#hooks-rust[Rust] and https://dredd.readthedocs.io/en/latest/hooks/js.html#hooks-nodejs[JS] are supported).
* https://dredd.org/en/latest/how-to-guides.html#integrating-dredd-with-your-test-suite[Easy integration with test suite] by using a config file.
* CLI can help https://dredd.org/en/latest/how-to-guides.html#continuous-integration[modify CircleCI config] for continuous integration.
* Uses https://dredd.org/en/latest/how-it-works.html#automatic-expectations[examples in specification] to generate expected responses.
* Can define https://dredd.org/en/latest/hooks/js.html#using-chai-assertions[custom expectations using Chai assertions].

===== https://github.com/RuntimeTools/chai-openapi-response-validator[Chai OpenAPI Response Validator] =====
* Works with Chai (which is compatible with Jest).
* Easy to incorporate to our api tests workflow.
* Example from GitHub repository:
[source,javascript]
----
// Set up Chai
const chai = require('chai');
const expect = chai.expect;

// Import this plugin
const chaiResponseValidator = require('chai-openapi-response-validator');

// Load an OpenAPI file (YAML or JSON) into this plugin
chai.use(chaiResponseValidator('path/to/openapi.yml'));

// Write your test (e.g. using Mocha)
describe('GET /example/request', function() {
it('should satisfy OpenAPI spec', async function() {

// Get an HTTP response using chai-http
chai.use(require('chai-http'));
const app = require('path/to/app');
const res = chai.request(app).get('/example/request');

expect(res.status).to.equal(200);

// Assert that the HTTP response satisfies the OpenAPI spec
expect(res).to.satisfyApiSpec;
});
});
----

==== Recommendation ====
Dredd, because it's well documented and has all the features we need. It looks like the main effort will be https://dredd.org/en/latest/how-it-works.html#making-your-api-description-ready-for-testing[preparing the specification] for testing.

==== JSON Schema integration ====
We currently use JSON Schema to validate the shape of the body of the response to `GET /
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't you expect to replace the JSON schema with our Open API doc?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that JSON Schema is more expressive and can be used for things such as server-defined client-side validation. OpenAPI supports a subset of JSON Schema and in the near future if will be fully supported.

In any case, using the $ref keyword we can reference .schema.json files in OpenAPI files. Until OpenAPI supports JSON Schema in full there might be some pain points, but there are ways to work around them.

swaps` and `GET /
swaps/rfc003/:id`. JSON Schema is supported by OpenAPI, https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schema-object[with some caveats]. There are https://apisyouwonthate.com/blog/solving-openapi-and-json-schema-divergence[ways to get around this situation], and full support for JSON Schema is https://github.com/OAI/OpenAPI-Specification/pull/1977[in the works].

=== How to generate the specification ===

==== Options ====

===== Automatically =====
* Switch to actix-web and use https://paperclip.waffles.space/actix-plugin.html[this experimental plugin].
* Wait for Rocket to https://github.com/SergioBenitez/Rocket/issues/297[implement this feature] and switch back to it.
* https://github.com/seanmonstar/warp/issues/89[Wait for this feature] to come to warp.

===== Manually =====
* Use https://github.com/swagger-api/swagger-editor[Swagger Editor] (over 5k stars on GitHub).
* Use a plugin for an editor/IDE (look at the editors listed https://openapi.tools/[here]).

===== Assisted =====
* Using https://inspector.swagger.io/builder[Swagger Inspector].
* Make API calls to a running cnd through the UI and generate part of the specification.

==== Recommendation ====
Unfortunately the tools aren't there yet to automatically produce the API specification from source code in Rust. There seems to be some interest for this, so it may come in the future. For the time being, we will have to write it ourselves. Fortunately, this specification will be custom-id:test-specification[tested] and we can use tools such as https://speccy.io/[speccy] to validate it.

=== How to visualise specification ===

==== Options ====

===== https://petstore.swagger.io/[SwaggerUI] =====
* Extremely popular (over 15k stars on https://github.com/swagger-api/swagger-ui[GitHub])
* RPC-style.
* Looks like this:
image::How_to_visualise_documentation/Swagger_UI_2019-08-29_18-16-23.png[scaledwidth=100%]

* Hides JSON bodies.

===== https://redocly.github.io/redoc/[ReDoc] =====
* Popular (over 1k stars on GitHub).
* Very https://github.com/Redocly/redoc/#deployment[simple] to set up.
* Three-column style.
* It looks very good:
image::How_to_visualise_documentation/redoc-demo_2019-08-29_18-29-34.png[scaledwidth=100%]

===== http://cheesestore.github.io/[Spectacle] =====
* Quite popular (about 1k stars on GitHub).
* Looks similar to ReDoc:
image::How_to_visualise_documentation/screenshot_2019-08-29_18-46-24.jpg[scaledwidth=100%]

==== Recommendation ====
ReDoc because it is easy and I think it looks nice.

=== What does the documentation include? ===

==== HTTP API Specification. ====
Models services.

==== JSON Schema. ====
Models data.

=== How to host documentation for current `master` HEAD ===
If we go for the recommended option of using custom-id:redoc[ReDoc], it's https://www.npmjs.com/package/redoc#tldr[very easy]:
luckysori marked this conversation as resolved.
Show resolved Hide resolved
luckysori marked this conversation as resolved.
Show resolved Hide resolved

. Include API specification in repository with cnd.
. Host a website on GitHub Pages (for example).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would that allow developers to access the API specification of various versions or just master?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking to @thomaseizinger, we see the publicly hosted API specification only supporting master.

For someone developing against the API locally, we recommend adding an endpoint which returns the specification to the HTTP API itself.

. Use a HTML tag that links to the API specification (there's even a https://www.npmjs.com/package/redoc#usage-as-a-react-component[React component]).
luckysori marked this conversation as resolved.
Show resolved Hide resolved

=== How to document extension link relation types? ===
I would argue that this is covered in https://github.com/comit-network/comit-rs/issues/843[the original issue]. Just replace `human-protocol-spec` key with a link to a static HTML page hosted on GitHub Pages (for example) where the meaning of `human-protocol-spec` is described.

=== Client-side validation ===

==== Context ====
* We already define custom-id:json-schema-integration[JSON Schemas] for some data objects returned from the API.
luckysori marked this conversation as resolved.
Show resolved Hide resolved
* We have https://github.com/comit-network/comit-i/issues/44[discussed] doing input validation on comit-i.
* We currently reproduce server-side validation on comit-i.

==== Purpose ====
* Improve user experience for users of clients of our API.
* Simplify the job of developers.

==== Proposal ====
* Define JSON Schemas for all data objects that our API returns.
* Offer a copy of these contracts to clients in a programmatically accessible format.
* Include link to in response header:
[source,html]
----
Link: <http://example.com/schemas/swap.schema.json#>; rel=”describedby”
----
* Use in comit-i to prove that it works.

==== References ====
* https://apisyouwonthate.com/blog/the-many-amazing-uses-of-json-schema-client-side-validation[Blog on client-side validation based on JSON Schema].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you descrive a bit more OpenAPI vs JSON schema? I am not clear on the concepts.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully clearer now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What commit made it clearer?

Copy link
Collaborator Author

@luckysori luckysori Sep 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ List of spike outcomes for COMIT network.
- [spike-0012](0012-release-strategy.adoc) - Release Strategy
- [spike-0013](0013-secure-http-api.adoc) - Securing the cnd HTTP API
- [spike-0014](0014-resume-swaps-after-restart.adoc) - Resume swaps after restart
- [spike-0015](0015-how-to-document-cnd-http-api.adoc) - How to document cnd's HTTP API

For new spike outcomes, please use [template.adoc](template.adoc) as basis.