This repository has been archived by the owner on Nov 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Resource prototypes #16
Open
goganchic
wants to merge
7
commits into
apiaryio:master
Choose a base branch
from
goganchic:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
df869bd
add common data description
goganchic 8df44bf
fix headers levels
goganchic 6816f8a
add variant with action prototypes
goganchic c7cd3b8
add info about disabling prototype for one action
goganchic 719bab7
rewrite rfc using MSON inheritance syntax
goganchic 1874b85
add base type for resource prototypes
goganchic 215e716
make separate section for resource prototypes
goganchic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
--- | ||
RFC: XXXX | ||
Author: Egor Baranov | ||
Status: Draft | ||
Created: 2017-05-03 | ||
Last Modified: 2017-05-03 | ||
--- | ||
|
||
# API Blueprint RFC XXXX: Resource prototypes | ||
|
||
## Table of Contents | ||
|
||
- [Abstract](#abstract) | ||
- [Motivation](#motivation) | ||
- [Rationale](#rationale) | ||
- [Backwards Compatibility](#backwards-compatibility) | ||
|
||
## Abstract | ||
|
||
This RFC proposes an ability to craete resource prototypes and use it to reduce | ||
code duplication. | ||
|
||
## Motivation | ||
|
||
When you describe big API several resources can have identical responses. | ||
Good examples of such problem are: | ||
|
||
* request format checks - when several requests can return common error like | ||
`WrongFormat` | ||
* limit rate - when API checks how many requests have user done during some | ||
period of time and any request can return error like `LimitExceeded` | ||
* authorization checking - some part of API can require authorization so several | ||
actions can return HTTP 403 forbidden | ||
* deferred actions - when API request don't perform its job synchronously but | ||
put them into queue and return an identifier back to user; such actions will | ||
have same response format | ||
|
||
All these cases leads to code duplication: you have to write the same response | ||
again and again. This problem can be cause of misspellings and logical errors. | ||
So ability to add common responses and headers in one place for multiple actions | ||
is required. | ||
|
||
## Rationale | ||
|
||
### Resource prototypes | ||
|
||
One of the possible solutions to reduce duplication is creating resource | ||
prototype and setting it to | ||
[resource](https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#resource-section) | ||
or | ||
[resource group](https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#def-resourcegroup-section) | ||
|
||
We have complicated API with several duplicate responses: | ||
|
||
```apib | ||
# Data Structures | ||
|
||
## Post | ||
|
||
+ title: `test` (string, required) | ||
+ body: `hello world` (string, required) | ||
|
||
## User | ||
|
||
+ name: `John Smith` (string, required) | ||
+ email: `[email protected]` (string, required) | ||
|
||
## Posts [/posts] | ||
|
||
### List posts [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (array[Post], required, fixed-type) | ||
|
||
+ Response 429 (application/json) | ||
+ Attributes | ||
+ status: tooManyRequests (string, required, fixed) | ||
+ waitFor: `10` (number, required) - wait before next request | ||
|
||
+ Response 400 (application/json) | ||
+ Attributes | ||
+ status: badRequest (string, required, fixed) | ||
+ errors (array[string], required, fixed-type) - list of errors in request | ||
|
||
### Show post [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (Post, required) | ||
|
||
+ Response 429 (application/json) | ||
+ Attributes | ||
+ status: tooManyRequests (string, required, fixed) | ||
+ waitFor: `10` (number, required) - wait before next request | ||
|
||
+ Response 400 (application/json) | ||
+ Attributes | ||
+ status: badRequest (string, required, fixed) | ||
+ errors (array[string], required, fixed-type) - list of errors in request | ||
|
||
## Users [/users] | ||
|
||
### List users [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (array[User], required, fixed-type) | ||
|
||
+ Response 429 (application/json) | ||
+ Attributes | ||
+ status: tooManyRequests (string, required, fixed) | ||
+ waitFor: `10` (number, required) - wait before next request | ||
|
||
+ Response 400 (application/json) | ||
+ Attributes | ||
+ status: badRequest (string, required, fixed) | ||
+ errors (array[string], required, fixed-type) - list of errors in request | ||
|
||
+ Response 403 (application/json) | ||
+ Attributes | ||
+ status: forbidden (string, required, fixed) | ||
|
||
### Create user [POST] | ||
|
||
+ Response 200 | ||
+ Attributes (User, required) | ||
|
||
+ Response 429 (application/json) | ||
+ Attributes | ||
+ status: tooManyRequests (string, required, fixed) | ||
+ waitFor: `10` (number, required) - wait before next request | ||
|
||
+ Response 400 (application/json) | ||
+ Attributes | ||
+ status: badRequest (string, required, fixed) | ||
+ errors (array[string], required, fixed-type) - list of errors in request | ||
|
||
+ Response 403 (application/json) | ||
+ Attributes | ||
+ status: forbidden (string, required, fixed) | ||
``` | ||
|
||
As you can see responses 429, 400 and 403 are duplicated several times. It is | ||
possible to extract response description into | ||
[Data Structures](https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#def-data-structures) | ||
section and it will help to reduce duplication but you have to write something | ||
like | ||
|
||
```apib | ||
+ Response 429 (application/json) | ||
+ Attributes (TooManyRequestsError) | ||
``` | ||
|
||
for every resource. It is possible to remove duplication completely using new | ||
proposed syntax: | ||
|
||
```apib | ||
# Data Structures | ||
|
||
## Post | ||
|
||
+ title: `test` (string, required) | ||
+ body: `hello world` (string, required) | ||
|
||
## User | ||
|
||
+ name: `John Smith` (string, required) | ||
+ email: `[email protected]` (string, required) | ||
|
||
## Authorized (Resource Prototype) | ||
|
||
+ Response 403 (application/json) | ||
+ Attributes | ||
+ status: forbidden (string, required, fixed) | ||
|
||
## Common Resource (Resource Prototype) | ||
|
||
+ Response 429 (application/json) | ||
+ Attributes | ||
+ status: tooManyRequests (string, required, fixed) | ||
+ waitFor: `10` (number, required) - wait before next request | ||
|
||
+ Response 400 (application/json) | ||
+ Attributes | ||
+ status: badRequest (string, required, fixed) | ||
+ errors (array[string], required, fixed-type) - list of errors in request | ||
|
||
# Group Blog (Common Resource) | ||
|
||
## Posts [/posts] | ||
|
||
### List posts [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (array[Post], required, fixed-type) | ||
|
||
### Show post [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (Post, required) | ||
|
||
## Users (Authorized) [/users] | ||
|
||
### List users [GET] | ||
|
||
+ Response 200 | ||
+ Attributes (array[User], required, fixed-type) | ||
|
||
### Create user [POST] | ||
|
||
+ Response 200 | ||
+ Attributes (User, required) | ||
``` | ||
|
||
In `Data Structures` section two prototypes were defined: `Common Resource` | ||
and `Authorized` with base type `Resource Prototype`. Both of them have some | ||
responses. To assign prototype for all resources of resource group you need to | ||
use such syntax: `Section name (Prototype Name)`. If section has nested section | ||
then all resources of nested section will have responses defined in prototype. | ||
`Users` resource group will have responces from `Common Resource` prototype | ||
(because it's a prototype of its parent group) and from `Authorized` prototype. | ||
|
||
It is possible to assign several prototypes for one resource or resource group: | ||
|
||
```apib | ||
# Group Blog (Common Resource, Authorized) | ||
``` | ||
|
||
It is possible when one prototype has its own prototype: | ||
|
||
```apib | ||
# Data Structures | ||
|
||
## Common Resource (Rate, Format) | ||
``` | ||
|
||
## Backwards Compatibility | ||
|
||
There will be no backward compatibility problems. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not like how we're adding serialisation into data structures. Data structures are already decoupled from the serialisation and this feels like a step backwards. The point of creating data structures is that they would be decoupled from the serialisations.
Data Structures are agnostic to serialisation of media types. With MSON, I can describe the data and defer the decision whether they will be send as JSON, XML or HAL over the wire.
I had some ideas about decoupling the serialisation and wrote then into #17 so we can decouple the serialisation from request/response bodies which could perhaps fit in here. But this would likely be more part of the larger picture of abstracting the protocol layer from API Blueprint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kylef imho you are trying to solve another problem. I see two independent problems:
I think we shouldn't mix these problems. I just want to solve small problem which would help to reduce api description dramatically. Decoupling is a bigger problem which can help to describe different API (not only JSON HTTP API) and it requires much more changes so I think it's a good idea to solve it now. My changes do not affect decoupling at all because it just repeats current response structure in new section. When we find solution for bigger problem it will be easy to make changes in resource section and the same changes in resource prototype section but for now it would be logically to make the same structure in resource and resource prototype sections.
I thinks
Data Structures
is not the best place forResource Prototype
items so I prefer to create another section calledResource Prototypes
and move all resource prototypes there. It will be more logically for users and also easier to implement.@kylef @pksunkara what do you think about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kylef I've created separate section for resource prototypes. Structure of resource prototype differs a lot from mson data structures, so it will be better for user to have resource prototypes in separate section because in this case API will be more readable and clear.