Quite often I fire up the node REPL and pull in some modules I've written to use on the command line. Unfortunately I often forget the exact way to call the various functions in those modules (there are a lot) and end up doing something like foo.dosomething.toString() to see the source code and recall the function signature.
In the interest of making code as "self-documenting" as possible, I wrote a small utility that uses dox to provide help for modules on the command line. It adds a help() function to a module's exported methods so you can get the dox / jsdoc comments for the function on the command line.
So now foo.dosomething.help() will return the description, parameters, examples and so on for the method based on the documentation in the comments.
It's still a bit of a work in progress, but it works nicely - provided you actually document your modules with jsdoc-style comments.
All the info is here: https://www.npmjs.org/package/doxli
Wednesday, September 17, 2014
Sunday, September 7, 2014
REST API Best Practices 4: Collections, Resources and Identifiers
Other articles in this series:
In Rest, collections and resources are accessed via HTTP URI's in a similar way:
members/ -- a collection of members
members/1 -- a resource representing member #1
members/2 -- a resource representing member #2
It may help to think of a REST collection as a directory folder containing files, although its highly unlikely that the member data is stored as literal JSON files on the server. The member data should be coming from a database, but from the perspective of a REST API, it looks similar to a directory called "members" that contains a bunch of files for download.
In case it's not obvious already, collection names should be nouns. Use the plural form for naming collections. There's been some debate over whether collection names should be plural (members/1) or singular (member/1). The plural form seems to be most widely used.
Getting a collection, like "members" may return
Approach #2, returning a partial representation (ie. first name, last name) of all resources in a collection is a more pragmatic way of returning enough information about the resources in a collection for the end user to make a selection to request further details, especially if the collection can contain a lot of resources. Actually, the directory listings on a website like http://vault.centos.org/ display more than just the hyperlink. They include additional meta-data like the last-modified timestamp and file size, as well. This is helpful for the end-user who's looking for an up-to-date file and wants to know how long it will take to download. It's a good example of returning just enough information about the resources for the end-user to be able to make a selection.
With approach #3, if a collection is small, you may want to return the full representation of all the resources in the collection as a big array. For large collections, it isn't practical, however. Github is the only RESTful API example I've seen that actually returns a full representation of all resources when you fetch the collection. I wouldn't consider #3 to be a "best practice", or recommend it for most use cases, but if you know the collection and resources will be small, it might be more effective to fetch the whole collection all at once like this.
The best practice for fetching a collection of resources, in my opinion, is #2: return a partial representation of the resources in a collection with just enough information to facilitate the selection process, and be sure to include the URL (href) of each resource where it can be downloaded from.
Only when a collection is guaranteed to be small and you need to reduce the performance impact of making multiple queries, consider bending the rules with approach #3 to return all the resources in one fell swoop.
Here's a practical example of fetching the collection of members using approach #2.
Request
GET /members
Host: localhost:8080
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
[
{
"id": 1,
"href": "/members/1",
"firstname": "john",
"lastname": "doe"
},
{
"id": 2,
"href": "/members/2",
"firstname": "jane",
"lastname": "doe"
}
]
In this example, some minimal information is returned about each of the members: first and last name, id, and the "href" URL where the full representation of the member resource can be downloaded.
Getting a specific resource should returns the full representation of that resource from the URL that contains the collection name and the ID of the specific resource you want.
RESTful resources have one or more identifiers: a numerical ID, a title, and so on. Common practice is for every resource to have a numeric ID that is used to reference the resource, although there are some notable exceptions to the rule.
Resources themselves should contain their numerical ID; the current best practice is for this to exist within the resource simply as an attribute labelled "id". Every resource should contain an "id"; avoid using more complicated names for resource identifiers like "memberID" or "accountNumber" and just stick with "id". If you need additional identifiers on a resource, go ahead and add them, but always have an "id" that acts as the primary way to retrieve the resource. So, if a member has "id" : 1, it should be fairly obvious that you can fetch his details at the URL "members/1".
An example of fetching a member resource would be:
Request
GET /members/1
Host: localhost:8080
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"id": 1,
"href": "/members/1",
"firstname": "john",
"lastname": "doe",
"active": true,
"lastLoggedIn": "Tue Sep 16 2014 08:37:42 GMT-400 (EDT)",
"foo": "bar",
"fizz": "buzz",
"qux": "doo"
}
Most of the examples you see online are fairly simple, but practical data models are often much more complex. Resources frequently contain sub-collections and relationships with other resources. API design in this area seems to be done in a mostly ad-hoc manner,but there are some practical considerations and trade-offs when designing APIs for more complex data models, which should be covered in the next post.
- REST API Best Practices: A REST Cheat Sheet
- REST API Best Practices: HTTP and CRUD
- REST API Best Practices: Partial Updates - PATCH vs. PUT
In Rest, collections and resources are accessed via HTTP URI's in a similar way:
members/ -- a collection of members
members/1 -- a resource representing member #1
members/2 -- a resource representing member #2
It may help to think of a REST collection as a directory folder containing files, although its highly unlikely that the member data is stored as literal JSON files on the server. The member data should be coming from a database, but from the perspective of a REST API, it looks similar to a directory called "members" that contains a bunch of files for download.
Naming collections
In case it's not obvious already, collection names should be nouns. Use the plural form for naming collections. There's been some debate over whether collection names should be plural (members/1) or singular (member/1). The plural form seems to be most widely used.
Getting a collection
Getting a collection, like "members" may return
- the entire list of resources as a list of links,
- partial representations of each resource, or
- full representations of all the resources in the collection.
Approach #2, returning a partial representation (ie. first name, last name) of all resources in a collection is a more pragmatic way of returning enough information about the resources in a collection for the end user to make a selection to request further details, especially if the collection can contain a lot of resources. Actually, the directory listings on a website like http://vault.centos.org/ display more than just the hyperlink. They include additional meta-data like the last-modified timestamp and file size, as well. This is helpful for the end-user who's looking for an up-to-date file and wants to know how long it will take to download. It's a good example of returning just enough information about the resources for the end-user to be able to make a selection.
With approach #3, if a collection is small, you may want to return the full representation of all the resources in the collection as a big array. For large collections, it isn't practical, however. Github is the only RESTful API example I've seen that actually returns a full representation of all resources when you fetch the collection. I wouldn't consider #3 to be a "best practice", or recommend it for most use cases, but if you know the collection and resources will be small, it might be more effective to fetch the whole collection all at once like this.
The best practice for fetching a collection of resources, in my opinion, is #2: return a partial representation of the resources in a collection with just enough information to facilitate the selection process, and be sure to include the URL (href) of each resource where it can be downloaded from.
Only when a collection is guaranteed to be small and you need to reduce the performance impact of making multiple queries, consider bending the rules with approach #3 to return all the resources in one fell swoop.
Here's a practical example of fetching the collection of members using approach #2.
Request
GET /members
Host: localhost:8080
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
[
{
"id": 1,
"href": "/members/1",
"firstname": "john",
"lastname": "doe"
},
{
"id": 2,
"href": "/members/2",
"firstname": "jane",
"lastname": "doe"
}
]
In this example, some minimal information is returned about each of the members: first and last name, id, and the "href" URL where the full representation of the member resource can be downloaded.
Getting a resource
Getting a specific resource should returns the full representation of that resource from the URL that contains the collection name and the ID of the specific resource you want.
Resource IDs
RESTful resources have one or more identifiers: a numerical ID, a title, and so on. Common practice is for every resource to have a numeric ID that is used to reference the resource, although there are some notable exceptions to the rule.
Resources themselves should contain their numerical ID; the current best practice is for this to exist within the resource simply as an attribute labelled "id". Every resource should contain an "id"; avoid using more complicated names for resource identifiers like "memberID" or "accountNumber" and just stick with "id". If you need additional identifiers on a resource, go ahead and add them, but always have an "id" that acts as the primary way to retrieve the resource. So, if a member has "id" : 1, it should be fairly obvious that you can fetch his details at the URL "members/1".
An example of fetching a member resource would be:
Request
GET /members/1
Host: localhost:8080
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"id": 1,
"href": "/members/1",
"firstname": "john",
"lastname": "doe",
"active": true,
"lastLoggedIn": "Tue Sep 16 2014 08:37:42 GMT-400 (EDT)",
"foo": "bar",
"fizz": "buzz",
"qux": "doo"
}
Beyond simple collections
Most of the examples you see online are fairly simple, but practical data models are often much more complex. Resources frequently contain sub-collections and relationships with other resources. API design in this area seems to be done in a mostly ad-hoc manner,but there are some practical considerations and trade-offs when designing APIs for more complex data models, which should be covered in the next post.
Subscribe to:
Posts (Atom)
Productivity and Note-taking
I told a friend of mine that I wasn't really happy with the amount of time that gets taken up by Slack and "communication and sched...
-
Update : Here are slides for this talk at OttawaJS: " Node.JS Module Patterns Using Simple Examples ". Update 2 : More Node.JS M...
-
tldr; https://github.com/73rhodes/sideflow This extension provides goto, gotoIf and while loop functionality in Selenium IDE. Selenium ...
-
This post is a continuation of REST API Best Practices 2: HTTP and CRUD , and deals with the question of partial updates. REST purists ins...