diff --git a/rfcs/common-data.md b/rfcs/common-data.md deleted file mode 100644 index d4be149..0000000 --- a/rfcs/common-data.md +++ /dev/null @@ -1,272 +0,0 @@ ---- -RFC: XXXX -Author: Egor Baranov -Status: Draft -Created: 2017-05-03 -Last Modified: 2017-05-03 ---- - -# API Blueprint RFC XXXX: Common Data - -## Table of Contents - -- [Abstract](#abstract) -- [Motivation](#motivation) -- [Rationale](#rationale) -- [Backwards Compatibility](#backwards-compatibility) - -## Abstract - -This RFC proposes an ability to add common responses and to multiple actions. - -## Motivation - -When you describe big API several actions can have identical responses. -For example you have 10 actions allowed for authorized user only, so each -of such actions can respond with 401. If you have some complex response you can -create named type and use it 10 times but even in this situation you have to -write same code 10 times. This problem connected not only authorization but -with other tasks. If you have common error in several actions you will have -exatly the same situation. If you want to change this code you have to change it -in 10 places. This problem can be cause of misspellings and logical errors. -So ability to add common responses in one place for multiple actions is -required. - -## Rationale - -### Common Data - -Common responses can be defined in an API Blueprint under an "Common Data" header. -Inside this header one or several Response sections are allowed. -Here is an example: - -```apib -# Group Authorized resources - -## Common Data - -+ Response 401 - -## Posts [GET /posts] - -+ Response 200 - -## Comments [GET /comments] - -+ Response 200 -``` - -This code equals to: - -```apib -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -+ Response 401 - -## Comments [GET /comments] - -+ Response 200 - -+ Response 401 -``` - -It is possible to have several "Common Data" sections: - -```apib -# Group Authorized resources - -## Common Data - -+ Response 401 - -## Common Data - -+ Response 500 - -## Posts [GET /posts] - -+ Response 200 - -## Comments [GET /comments] - -+ Response 200 -``` - -This code equals to: - -```apib -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -+ Response 401 - -+ Response 500 - -## Comments [GET /comments] -+ Response 200 - -+ Response 401 - -+ Response 500 -``` - -Common Data section influences to current actions group and all internal actions -groups, but not neighbors: - -```apib -# Group Authorized resources - -## Common Data - -+ Response 401 - -## Posts [GET /posts] - -+ Response 200 - -# Group Authorization - -## Auth [POST /auth] - -+ Response 200 -``` - -This code equals to: - -```apib -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -+ Response 401 - -# Group Authorization - -## Auth [POST /auth] - -+ Response 200 -``` - -`/auth` action has no 401 response, because it is located in separate group. - -### Action prototypes - -Another variant of solving problem is using actions inheritance. In this -situation we creates base action and all actions of group inherites its -responses: - -```apib -# Group Authorized resources - -# Prototype - -+ Response 401 - -## Posts [GET /posts] - -+ Response 200 -``` - -In this example we have created unnamed prototype for actions group Authorized -resources. In this groups and all its subgroups all actions will inherit -responses from the prototype. - -Code above equals to: - -```apib -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -+ Response 401 -``` - -We can set several prototypes for one group: - -```apib -# Group Authorized resources - -# Prototype - -+ Response 401 - -## Prototype - -+ Response 500 - -## Posts [GET /posts] - -+ Response 200 -``` - -We can created named prototype. Advantage of this variant is an ability to -disable prototype for some actions group: - -```apib -## Prototype Authorized - -+ Response 401 - -After previous line all actions will have 401 response - -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -# Group Authorization - -## Unuse Prototype Authorized - -In this section there will be no 401 response because we have diabled prototype -Authorized - -## Auth [POST /auth] - -+ Response 200 -``` - -It is possible to disable prototype for one particular action: - -```apib -## Prototype Authorized - -+ Response 401 - -After previous line all actions will have 401 response - -# Group Authorized resources - -## Posts [GET /posts] - -+ Response 200 - -# Group Authorization - -## Auth [POST /auth] - -Disable prototype Authorized only for this action - -+ Unuse Prototype Authorized - -+ Response 200 -``` - -## Backwards Compatibility - -If anyone use "Common Data" or "Prototype" headers in the documentation after -this RFC it will treat as special section instead of regular markdown header. -If there is no such section in the documention there will be no backward -compatibility problems. diff --git a/rfcs/resource-prototypes.md b/rfcs/resource-prototypes.md new file mode 100644 index 0000000..ae35a7a --- /dev/null +++ b/rfcs/resource-prototypes.md @@ -0,0 +1,242 @@ +--- +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: `user@example.com` (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 +# Resource prototypes + +## Common Resource + ++ 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 + +# Data Structures + +## Post + ++ title: `test` (string, required) ++ body: `hello world` (string, required) + +## User + ++ name: `John Smith` (string, required) ++ email: `user@example.com` (string, required) + +## Authorized + ++ Response 403 (application/json) + + Attributes + + status: forbidden (string, required, fixed) + +# 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 `Resource prototypes` section two prototypes were defined: `Common Resource` +and `Authorized`. 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 +# Resource prototypes + +## Common Resource (Rate, Format) +``` + +## Backwards Compatibility + +If anyone use `Resource Prototypes` headers in the documentation after this RFC +it will treat as special section instead of regular markdown header. If there is +no such section in the documention there will be no backward compatibility +problems.