3

So, there are many times where I have to do things with my REST API that seem outside the boundaries of REST. In this particular instance I need to have an endpoint that checks whether a member is eligible for free training or not.

I could possibly add this information onto the Read endpoint but that means that its going to get returned on every read call. This is fine this time, but what happens when there are 100 checks and now we return 100 fields that are only needed at certain times? It just gets bloated.

I wouldn't mind making an endpoint like /member/{id}/eligibleForFreeTraining and just return a true or false but that is not CRUD or REST.

Where do these kinds of calls fit into a REST'ish API?

  • 1
    Why not have a resource called eligibility? – Can't Tell Jul 2 '16 at 14:33
7

Add it on to the resource. If you end up with so many of these "does this special promotion apply" questions that the resource ends up huge, split them out into related resources. For instance, GET /member/{id}/promotions. Rather than relying on URL structure, you may also wish to try using Link Headers to communicate via the /member/{id} resource where its promotions are located, or putting all promotions in a top level /promotions collection that can be filtered by member (e.g. /promotions?member=/member/{id}).

In general, when you have related additional information that's only useful in certain contexts, represent it as a separate resource that interested parties can reach from the first resource. Additionally, don't think "I need to check X", think "I need a resource that represents the result of checking X". The /member/{id}/promotions resource represents the server checking what promotions apply to a specific member and giving them to you. The server does the checking and logic. The client just asks for resources.

  • 1
    +1 for "The server does the checking and logic. The client just asks for resources." This sentence just made something click inside my head with the whole RESTful concept. – jtate Sep 12 '17 at 17:48
1

I wouldn't mind making an endpoint like /member/{id}/eligibleForFreeTraining and just return a true or false but that is not CRUD or REST.

There's precedent for that; for instance: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred

I could possibly add this information onto the Read endpoint but that means that its going to get returned on every read call. This is fine this time, but what happens when there are 100 checks and now we return 100 fields that are only needed at certain times? It just gets bloated.

One answer is that you can have multiple representations, that have different levels of details. The RESTful way to do that would be to have different media types that describe the different representations.

For example, the Apis for the Sun Cloud defines a number of different JSON representations, identified by distinct vendor media types.

It's always been allowed to implement resources with more than one media type representation, and nothing in the "rules" prevents you from having more than one representation with the same media type suffix.

The client request for the resource would specify the appropriate media type, and the server would offer it up, if available.

The RESTful way to communicate about the available media types is to announce their availability via hypermedia controls. In other words, in addition to providing the client with a link that specifies the "standard" media type for the resource, you provide it with alternative links that it can use in other circumstances.

EDIT allowed, but not necessarily encouraged.

We encourage resource owners to only use true content negotiation (without redirects) when the only difference between formats is mechanical in nature.

-- Fielding, 2006

That would favor, as Jack noted in the comments, using a different logical resource for the different representations you want to support.

That said, it's probably worth pointing out that in a REST application (which is to say, if your API is providing a protocol), you wouldn't need to tell the client about the state of the flag, but instead use the state of the flag to determine whether or not to include links to other resources in the representation of the resource that you send to the client.

For your example, that would mean that you would include an "Enroll in Free Training" link to eligible members, and withhold it when members are not eligible, with the understanding that the client only acts on those links that have been provided to the client as part of the application state.

  • "Multiple representations with different levels of detail" is not a good idea. The URL alone should determine what data the returned resource representation contains, different content types may provide the data in different formats but they should all provide semantically equivalent data (within reason). Asking for different data should be done through URL-based mechanisms, e.g. query parameters. Otherwise you're hiding two different "things" in the same URL. – Jack Jul 2 '16 at 3:40
  • Have you got a cite for that? From the point of view of a hypermedia client, the spelling of the URI is opaque. The client simply chooses the appropriate hypermedia control(s) and follows the link. RFC 7234 requires that caches along the way do the right thing if the Vary header is set correctly. What have I missed?. – VoiceOfUnreason Jul 2 '16 at 5:06
  • It's not about the spelling of the URI, it's about whether different URIs are used. Different content types don't have different URIs, so they should semantically represent the same thing. One content type having data with semantic meaning for the resource that other content types do not breaks this assumption, because now this content type is basically a different resource, not a different view of the same resource. This is why query parameters are used for filtering/shaping output - it changes the URI. – Jack Jul 2 '16 at 5:27
1

I wouldn't mind making an endpoint like /member/{id}/eligibleForFreeTraining and just return a true or false but that is not CRUD or REST.

REST is not CRUD.

REST is REpresentational State Transfer. You are transferring the state of resources between the client and the server. What the client or server does with those representations is up to it. At the REST communication level your protocol is not concerned about about the actions the client or the server will perform on the representation once it gets it. That is not HTTP's concern.

Resources are an abstraction layer all on their own, they do not have to map to any internal data model on your server, nor do the HTTP verbs (GET, POST, PUT, DELETE etc) have to map to CRUD commands on your data model. On your server you might have one database table and 20 resources exposed to the client. Or when your client PUTs a representation onto a server the server might store that in a database, in 20 databases, in a flat file, in memory. HTTP doesn't care.

You might be using a web framework like Rails that fundamentally doesn't get this point, but don't assume this is the right way to do it just because a framework does it that way. You can have as many resources exposed on your HTTP interface as you feel are necessary.

This is fine this time, but what happens when there are 100 checks and now we return 100 fields that are only needed at certain times? It just gets bloated.

Unless you have a very good reason to care about that (e.g your resource is megabytes in size), don't worry about that. It is premature optimisation to build a URL scheme for that specific use case. From a practical point of view it will make very little difference to the transfer of the data if the Member resource has 5 fields of a 100 fields

It is far easier to say this is the URL of the resource, use it for what ever you want. The client might need just the name of the member. It might just need the age of the member. It might not care about the name or the age of the member it might just want to see if it is free for training.

You vastly increase the complexity of your system if you try to build URL end points of each use case of why the client might need the data. It is far easier to simply say to the client "Here is the resource, have at it" and let the client decide what it wants out of that resource.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.