Services REST server: Best practices for DRY when implementing custom endpoint for a custom model

texas-bronius's picture

I've implemented Services just a few times now from out of the box Drupal function to custom endpoints, and the current one is my most ambitious (and most meticulous) effort. I want to build it in the way that makes the most sense, and I feel informed enough now to have a decent discussion about best practices.

For a REST server hosted by the Services module, the request flow looks like this, right?

My actual model/controller being exposed by this REST API enforces all the business logic user security, user input validation and sanitization, and of course the meat of the work being done. However, I find myself vacillating between trying to make a generic access_callback that can enforce part or all of the authentication and authorization -just because Services provides for it- and instead peppering in the same kind of repetitive security code in each route callback itself (which in turn can raise services_error(...) of course). So maybe I don't need to utilize the route's access callback, but then how should I write my code to be DRY for each endpoint?

A similar discussion for parameter validation. I have PUT and POST params in the json "data" payload. I have found that validating parameters is pretty neat as far as a documenting standpoint, but this does make the callback have to be a little more rigid (fixed params), and that itself is really just a wrapper for the underlying object it calls (read: lots of repeated php function argument variables to keep straight). On this, too, I vacillate between wanting to leverage ootb Services endpoint configuration (see side note on 400 vs 401 response) and rolling my own either per route or as an overall params parser, validator, and service_error() raiser.

Has anyone got some experience trying it both ways and can provide some guidance?

Comments

One Arg Only

tyler.frankenstein's picture

I've battled with a similar situation/problems over the years and have settled on always using a single argument for my custom service resources:

          'args' => array(
            array(
              'name' => 'data',
              'type' => 'array',
              'description' => 'The data dude.',
              'source' => 'data',
              'optional' => FALSE,
            )
          ),

That way I can always just send a single JSON object as the payload, then process/validate/access-check individual properties within the JSON data delivery.

Thanks Tyler

texas-bronius's picture

Thank you - I just wanted to hear it from someone else already really familiar with the module. Yes, this is exactly what I'm talking about, and this way there may even be more clarity as to what's going on when and why. Biggest mental hurdle for me was intentionally walking away from ootb helpers provided by the services module.

Cheers
-Bronius