1

I'm currently working on a REST API, trying to design it with most best practices as possible.

I work with Symfony2 PHP framework but some of my questions are valid for any REST API i guess.

Starting from the base design for a particular resource :

GET        /resource            - Get all resources
POST       /resource            - Create resource
GET        /resource/{id}       - Get resource with id={id}
PUT|PATCH  /resource/{id}       - Edit the resource with id={id}
DELETE     /resource/{id}       - Delete the resource with id={id}

Supposing my resource has complex rules while updating.

  1. It has a "status" field, (a float for example), that can be updated only by following a particular scheme
  2. It has a "schedule" field (a datetime), with different choices available that are not always the same

How am I supposed to expose those rules to the API consumer ? For the schedule field, how am I supposed to provide the different choices available at the current time ?


About the Symfony server-side part, I followed most of the recommandations of this walkthrough : http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/

My POST, PUT & PATCH actions are handled with Symfony Forms, so most of the rules are processed by Symfony constraints/validations features.

But form binding is quite limited, let's supposed I want to trigger a particular event if the user change the status field from 2 to 3? What is the best way to do that ?

Thanks in advance.

Florian Klein
  • 8,692
  • 1
  • 32
  • 42
Thomas Piard
  • 1,209
  • 2
  • 15
  • 25
  • i dont see your problem with form binding. when a user is changing the status from 2 to 3. you load the entity, bind the entity to the form, give the Put/Patch data and it will only update this fields. if you need events, you can bind them directly to the entity. so you post update logic is bind to your model and not to your api. see lifecylce for how: http://symfony.com/doc/current/book/doctrine.html#lifecycle-callbacks – Rufinus Aug 01 '14 at 13:12
  • So in my case, the best way is to set up a "preUpdate/postUpdate" lifecycle callback and monitor status changes ? Does it provide a way to detect something like : previous status was 2, it's going to be 3 ? – Thomas Piard Aug 01 '14 at 14:12
  • i use a finite state maschine for such things. https://github.com/K-Phoen/DoctrineStateMachineBundle .. may be to much for your case, but i guess you can look how the event hooks are implemented. – Rufinus Aug 01 '14 at 18:37
  • have a look at http://amundsen.com/media-types/collection/format/#objects-template – Florian Klein Aug 07 '14 at 11:19
  • what event do you want to trigger and when ? BTW, form binding is not limited at all, form events are very powerful. – Florian Klein Aug 07 '14 at 11:20

3 Answers3

1

HTTP has another verb you aren't using: OPTIONS. You can use this to list the schedule options.

Here's a blog article about it: http://zacstewart.com/2012/04/14/http-options-method.html

As for updating the status, I would reuse POST and include an action in the field. Example:

POST
{
    "type": "update",
    "status": 3
}

Modified REST:

GET        /resource            - Get all resources
POST       /resource            - Create resource
GET        /resource/{id}       - Get resource with id={id}
PUT|PATCH  /resource/{id}       - Edit the resource with id={id}
DELETE     /resource/{id}       - Delete the resource with id={id}
OPTIONS    /resource/{id}       - Retrieve options of resource with id={id}

Keep in mind that you can pass params along in the body for everything but GET and you can pass any params in the URL for GET.

Steve Tauber
  • 9,551
  • 5
  • 42
  • 46
  • 1
    Actually, PUT/POST are not reversed here, see the HTTP spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5 – kix Aug 08 '14 at 11:45
  • You are correct. I had misread that on stack. Here's a question that gets it right: http://stackoverflow.com/questions/630453/put-vs-post-in-rest – Steve Tauber Aug 08 '14 at 12:28
0

I have zero knowledge on Symfony2, so I'll just concentrate on your more generic REST how-to qustion about exposing rules.

  • Give the consumers of your REST API a documentation. It's the first thing they will hit before actually playing with your API. Use tools for that, from auto-generated help pages to 3'rd party providers like Apiary.io or alike.

  • Create meaningful responses when consumers send "wrong" requests: use correct http response status codes (Bad request, Conflict, etc.) when request parameters are missing or invalid. If your REST api is relaxed, it can also include information about what went wrong and how to resolve the problem in the response body. What worked well for me in the past was to have a generic ErrorMessage entity that was returned upon each non-successful request, containing a title, an error description, and a dedicated more technical "dev-description" which can be enabled/disabled for test/production on the server side. In my case, my consumers all know that they can get either the expected response entity in case of success, or that generic ErrorMessage entity in the response in case of failure.

  • If you can desribe your rules, why not provide those as meta information for your service? Eg. in my case I know I have a set of parameters, each having a set of available options. Think of the parameters as the key in a query string, and the options as the values for that key. In a complex world, parameter options depend on other parameter options, eg. in my case the available options for parameter B are dependent of what option(s) are "selected" for parameter A. I can expose those dependencies by providing a "metadata" resource in my REST api, eg. a JSON stucture listing all parameters and all options for those parameters, and for each option adding a "requires" section desribing that that option is only "available" if parameter xy has selected option p and q. This allows my consumers to - with a single request to that meta data resource - create a "state-machine" on the client side. I hope you get the picture.

codeclash
  • 2,053
  • 19
  • 17
0

Here is my understanding of REST-full way to handle updates and advertise update operations to API client.

This is based on this wonderful book and Fowler's article about REST with some additions of File Levels of Media Type and article about Restfull CQRS. Basically you use PUT for update and pass the operation via content type and advertise content type via mediaType in hypermedia controls.

All operations which are available for current state of your resource are listed among hypermedia controls which are passed with representation of resource like this:

<myresource>
  <status>ACTIVE</status>
  <some-field with-attribute="value"/>
  <some-other-field/>
  <!-- other fields representing state of resource -->

  <link rel = "self"
    uri = "/resource/1234"/>
  <link rel = "/linkrels/resource/changeStatus"
    uri = "/resource/1234"
    mediaType = "application/vnd.myapp+xml;domain-model=ChangeStatusCommand"/>
  <link rel = "/linkrels/resource/changeSchedule"
    uri = "/resource/1234"
    mediaType = "application/vnd.myapp+xml;domain-model=ChangeScheduleCommand"/>
  <link rel = "/linkrels/help"
    uri = "/help/resource"/>
</myresource>

Links together with mediaType gives enough information what command is allowed. In many cases this should be something very specific to current state of resource. For example if you can move it from status ACTIVE to TRASHED than command should be named not StatusChange but TrashCommand and so on.