-
Notifications
You must be signed in to change notification settings - Fork 0
strawman1
This is intended as a "kitchen-sink" example expressing most of the features mentioned in the original GitHub issue discussion. I've used of nested JSON schemas to describe parameters and response data. Also, I'm using URI Templates to describe URLs.
For this example I describe a simple API for setting and retrieving localized messages. This is a likely a silly example, but hopefully it's understandable.
---------------------- --------- ------------------------ --------------
Resource Methods Representation Status Codes
---------------------- --------- ------------------------ --------------
/{locale}/{messageId} GET, PUT message format (string) 200, 201, 302
/fallback/{locale} GET, PUT language format (string) 200, 201
---------------------- --------- ------------------------ --------------
To update or create a new localized message you PUT a string value to it's /{locale}/{messageId} URI. To assign a fallback locale for missing messages, you PUT a locale name to /fallback/{locale}.
{
resources: [
{
id: "LocalizedMessage",
doc: "A localized message",
path: "/{language}/{messageId}", // URI template
methods: {
GET: {
doc: "Retrieve a message",
statusCodes: [ 200, 302 ]
},
PUT: {
doc: "Update or create a message",
statusCodes: [ 201 ],
body: { type: "string" },
examples: [
{
path: "/en_US/greeting",
body: "Hello, world!"
},
]
}
},
parameters: {
locale: {
description: "A standard locale string, e.g. \"en_US.utf-8\"",
type: "string",
pattern: "[a-z]+(_[A-Z]+)?(\\.[a-z-]+)?"
},
messageId: {
description: "A free-form message string",
type: "string",
pattern: "[a-z_]+"
}
},
representations: ['application/json', 'text/plain'],
schema: { type: "string" },
},
{
// This resource has no human-readable documentation, but still provides some info on how to use it.
id: "FallbackLocale",
methods: {
GET: { statusCodes: [ 200 ] },
PUT: { statusCodes: [ 201 ] }
},
parameters: {
locale: {
type: "string",
pattern: "[a-z]+(_[A-Z]+)?(\\.[a-z-]+)?"
}
}
}
]
}The main advantage here is the ease of use. It is easy to build this list from a typical sinatra like router. You just push each method into the collection without worrying about consolidating the methods into a coherent mashed view. I like the unified view but it is a bit less workable implementation wise. How does the code which generates this JSON looks like?
Thinking about the tools there is strength in the fact that each item stands on it own
[
{
id: "LocalizedMessage",
doc: "Retrieve a message",
path: "/{locale}/{messageId}", // URI template
method: "GET",
statusCodes: [ 200, 302 ], // can also be found under response
params: {
locale: {
doc: "A standard locale string, e.g. \"en_US.utf-8\"",
style: "template",
type: "string",
validations: "[a-z]+(_[A-Z]+)?(\\.[a-z-]+)?" // this can be a string (regexp) or an array of specific rules
},
messageId: {
doc: "A free-form message string",
style: "template",
type: "string",
validations: "[a-z_]+"
}
}
},
{
id: "LocalizedMessage",
doc: "Update or create a message",
path: "/{locale}/{messageId}", // URI template
method: "POST",
statusCodes: [ 201 ],
params: {
locale: {
doc: "A standard locale string, e.g. \"en_US.utf-8\"",
style: "template",
type: "string",
validations: "[a-z]+(_[A-Z]+)?(\\.[a-z-]+)?" // this can be a string (regexp) or an array of specific rules
},
messageId: {
doc: "A free-form message string",
style: "template",
type: "string",
validations: "[a-z_]+"
}
},
request: {
representations: [
{ type: "application/text" },
{
type: "application/json",
schema: "http://json.schema.url.com",
// we can have a construct resembling params
// which will define the json fields in case the format is trivial
body: {
message: {
type: "string",
required: true
}
}
],
examples: [
{
path: "/en_US/greeting",
body: "Hello, world!"
},
{
path: "/en_US/greeting",
body: { "message": "Hello, world!" }
}
]
}
}
]- I like the noun/verb delineation of resources and methods, but perhaps it's too verbose?
- What do others think of URI templates? The specification defines "levels", where level 1 is simple string substitution + URL encoding, and levels 2 and 3 add more features (such as expressing query parameters and hash-fragment URL portions). I feel that requiring at least level 1 templates is not too onerous a burden for implementations.
[saary] I agree with the level 1 templates, the only alternative I know of is the sinatra style paths (/resource/:resourceId)
- What do others think of JSON schema? There's a fair bit of tooling built for it already and it would allow a client to validate (JSON) request bodies before sending them, as well as responses. The trade-off is that it's JSON-only, so some sort of tool for translating schemas to other serialization formats might be desirable.
[saary] I think JSON schema is a good option and we can allow an optional schema link for requests and responses.
- There's a lot of schemas defined in-line here. For a larger API where certain parameters are likely to be repeated, it would be nice to provide hyperlinks instead.
[saary] not sure about this one, I definitely about the request/response schema but other than that there is a lot of benefit of having the metadata at one location without multiple links. Remember that the metadata will be returned gzipped so it will cost that much even with a lot of duplications.
- Stating that a URI parameter is a string is redundant.
[saary] agreed this should be optional in this case
- What things MUST vs. SHOULD be provided?
- Hyperlinks to representation definitions in addition to known mime-types?
[saary] sounds good, we can add a field to the representation element
[saary] One of the things that we discovered while using docRouter was that it is beneficial to support the addition of user defined fields. By that I mean we do not validate the metadata it self. If a developer chose to add an additional custom 'authentication' item we just bubble it through as is. After running a bit with docRouter we actually removed stuff from our "spec" as we simply never used them.