jump to navigation

A Sane REST October 3, 2016

Posted by PythonGuy in Uncategorized.
add a comment

I’ve complained about REST numerous times, but I think I have a way of making it sane and useful.

My first design goal was compatibility with the huge variety of REST clients and servers out there. By “compatible”, I mean that it should work more or less, or be super-imposable on the system. That is, the system I describe here should be at least a subset of the features the clients or servers provide. I want to take advantage of all the tools and resources out there, but I don’t want to use peculiar features of one or the other.

The second design goal was simplicity. I want people to “get” it at a fundamental level, and see how to make their REST server compatible without having to think too hard.

Here’s the overview. I’m going to use the customer object as an example.

  1. There are three types of resources: Group Resources, Item Resources, and Method Resources.
  2. Group Resources live at /customers/. You can GET or POST. You cannot DELETE.
    1. GET will grab a subset of the customers. I call this “find”. You can specify various filter parameters based on the attributes of the object (you can get inventive here), but you must support the following parameters.
      • page: The page number, 1-based. This can be specified.
      • items_per_page: The number of items per page. This can be specified.
    2. POST will add an item.
  3. Item Resources live at /customers/:id. You can GET, PUT, or DELETE. Optionally, you can PATCH, but you really shouldn’t have objects with so many attributes that it’s necessary.
    1. GET will fetch the item.
    2. PUT will update the item’s attributes.
    3. DELETE will remove the item.
  4. Method Resources live at /email/. Method names are typically verbs. You can GET or POST. Either way, it’s the same.

Parameters are specified either in the URL GET parameters or the POST/PUT bodies. For POST and PUT, you can also specify parameters via the URL.

It is encouraged to use JSON as the POST/PUT body. However, if you use form encoded parameters, the following convention applies:

  • If a parameter is specified once, it is considered a single value.
  • If a parameter is specified multiple times, it is considered part of a list.

Don’t make it any more complicated than that.

I haven’t really decided what conventions I’ll use for documentation and such. I assume that Swagger is good enough and use those conventions.

Only the following HTTP status codes are allowed:

  • 200 means it all went OK. The response is JSON-encoded.
    • GET to a Group Resource has the following parameters:
      • page: The page number, 1-based.
      • items_per_page: The number of items per page.
      • first_item: The index of the first item, 0-based. This is (page-1)*items_per_page.
      • last_item: The index of the last item+1, 0-based. This is (page)*items_per_page, or total_items, whichever is less.
      • total_items: The total number of items (if available).
      • next_page: If there is a next page, the next page number goes here.
      • prev_page: If this is not page 1, the previous page number goes here.
      • results: The results, a list of items.
    • POST to a Group Resource returns the new object, as for the GET to the Item Resource.
    • GET to an Item Resource returns the object.
    • PUT to an Item Resource returns the object.
    • DELETE to an Item Resource returns “” or {}
    • GET or POST to a Method Resource returns the response.
  • 404 means the resource doesn’t exist or you don’t have authorization to access it.
  • 401 means you are not authenticated and you need to be to access those resources. This is a cue to the client that it needs to log in again.
  • 500 is for all other errors.
  • For all the errors, a JSON-encoded object with the following parameters are returned:
    • code: The error code or name. In Python, this would be the exception name.
    • description: A human-readable description of the error, hopefully with suggestions on how to fix it.
    • stacktrace: In non-production environments, this would have the stacktrace.

That’s all there is to it. Pretty simple and straightforward, and it should be compatible with most clients and servers out there.

URI vs. URL vs. URN October 3, 2016

Posted by PythonGuy in Uncategorized.
5 comments

Sometimes people confuse URLs with URIs.

Here’s how I keep track of what the difference is.

A URL is a string of text that points you to something on the internet you can download. The “L” means “Location”.

A URN is a string of text that points you to something that exists in the real world but not on the internet. The “N” means “Name”. These are things like the ISBN of a book.

A URI is a string of text that can be a URL or URN.

I know this isn’t very precise, but it should be helpful.

Please don’t use URI when you mean URL. If you are describing something on your server, then it’s a URL. If you’re describing an ephemeral concept that can’t exist on a server, then use URI.