RESTful resource with an expensive property - rest

I have a resource /messages.
In my java code, the Message interface looks like this:
interface Message {
public int getID();
public int getPostingUserID();
public String getText();
public int getRelevance();
}
For example, /messages/7 will give the following:
{ id: 7, postingUserID: 102, text: "tabs are better!", relevance: 10.3 }
Unfortunately, getRelevance() is quite expensive to calculate on-the-fly, and is only needed for perhaps a tenth of the queries. I don't want to calculate it when I don't need it.
So, I can see a few options:
/messages/7?includeRelevance=true to tell it to calculate the relevance, otherwise don't include it in the response
/messages/7/relevance as a separate request, and calculate it then
/relevances?forMessageID=7 as a separate request, and calculate it then
Which option is the most RESTful?
Thanks!

I would tend to go for /messages/7/relevance in this situation, and I'd make sure that the document returned when fetching /messages/7 includes a URL to the relevant relevance resource (for HATEOAS discoverability, of course).

The most RESTful way to do this (I believe, and could definitely be wrong) is to define 2 different media-types.
The client can request a specific one with the Accept: header, and you could default to the minimal one.

Related

REST URL for transforming one resource into another resource

I am struggling to come with proper REST URL for converting one resource into another. The API method does not do any CRUD operations but instead transform/convert one resource into another type of resource.
I have 2 resources Workunit and Document. I have 3 operations on these two resources
1> trasform Workunit into Document
2> sync Workunit into Document (different logic than transform)
3> transform Document into Workunit
and i have the following urls
[POST] api/v1/workunits/transform
[POST] api/v1/workunits/sync
[POST] api/v1/documents/transform
problem here is action is a part of REST URL
any suggestions?
problem here is action is a part of REST URL
That's not a problem - clients don't depend on the URL for semantics, so you can use any spelling you like; api/v1/4dc233fa-c77c-49d7-b7d6-296ffeb89612 is perfectly satisfactory.
It's analogous to having a verb as a variable name -- it may not be in keeping with your local coding standards, but the compiler doesn't care. So too is it with your URL and the general purpose components that use it.
Choosing a good identifier is like choosing a good name; it requires having a clear understanding of what the thing is. In the case of URI/URL, the thing being identified is a resource, which is to say something that is described by a document. GET/POST/PUT/DELETE and so on are all requests that we do something interesting with the underlying document.
So the usual pattern might be to POST a transform message to the workunit resource, or to POST a transform message to the Document resource, or to POST a sync message to the workunit resource.
Hmm, that last one sounds backwards; if the workunit is unchanged, and the Document is changed by the sync, then you would probably send a sync message to the Document resource.
So if I have /api/v1/documents/1, and I need to sync it, then I would normally use POST /api/v1/documents/1, with the sync semantics described in the message body (on the web, that would usually be an application/x-www-form-urlencoded representation of the sync message).
But it could just as easily be a message that says "Sync documents/1 with workitem/2" that I POST to the todo list for the synchronizer.
We are just putting documents politely into the server's in-tray, so that it can do useful work. The in-tray can have whatever label you want.
It is fine with given situation.
Nevertheless, if I am getting you right it may be a good idea to create two different controllers.
It's up to you but think of changing structure a little bit:
Separate the logic of Transformation and Sync into two different controllers, so you can avoid URL issue.
TransformationController
[Route("api/v1/transformation-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> TransformWorkunits()
{
//logic
}
[HttpPost("documents")]
public Task<Response> TransformDocuments()
{
//logic
}
}
SynchronizationController
[Route("api/v1/synchronization-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> SyncWorkunits()
{
//logic
}
}
So the URLs will be:
[POST] api/v1/transformation-controller/workunits
[POST] api/v1/synchronization-controller/workunits
[POST] api/v1/transformation-controller/documents
So this is a way to avoid verbs and fit REST rules.
If there will be more objects to transform/sync from and into, then you'll have to improve this approach.

How to design calculation API in RESTFul way?

I'm trying to design an API to calculate a result based on inputs.
Real business:
The API compares two securities portfolios (source and target) and return the orders, the consumer gets the orders, so he/she can then places those orders to adjust portfolio from source to target.
If this is hard to be understood, then here's a similar scenario:
The API compare two text, then return the difference of the 2 texts.
It is a little bit different from the classic CRUD, because the inputs and output are different resources
My first thought is like this:
POST /api/difference
{
'source': { ... },
'target': { ... }
}
But, it will be conflict with the classic payload:
POST /api/difference
{
'lineNumber': ...,
'isAdded': ...
}
Questions:
Should I use a media-type to distinguish the the input payloads? What a 'resource' should be in this case?
What should the API look like if I also want to place the orders (or apply the text diff) in the same time when the API is called?
Iam not sure whether I understand your problem correctly, but in general it
depends on whether the resources are already persisted in the system. In case
both resources are already available in the system I would simply build an URI
like /portfolio/{source_id}/difference/{target_id} which returns the diff
result. If only the source exists I would probably use something like:
POST /portfolio/{source_id}/difference
{target}
If both resources are not available I would probably consider to first persist
such a resource and make then the comparison.
If I understood you correctly, there already exists the resource POST /api/difference and hence you are looking to change MIME type. Instead, why don't you go with the first approach and change the resource name? For example,
POST /api/compare
{
'source': { ... },
'target': { ... }
}

Best practice for filtering results from a RESTful API call?

I'm defining a RESTful API for a TV broadcaster, specifically what the path should look like when asking for a subset of data. For example if I wanted to get the whole content for a particular channel, language on that channel between a specific date, how would I filter by date? The path below seems too long:
endpoint.com/content/channels/{channel_name}/language/french/from/20160701/to/20160801
An alternative I saw is to 'treat the search as a resource' and POST the date range filters to it in the request body, as mentioned here on SO: (How to design RESTful search/filtering?)
Any thoughts?
I will suggest you use #QueryParam annotation to filter your resources by getting it from URI.
To filter the resource you can use an URI like
/channel_name?language=french&from=20160701&to=20160801
Using JAX-RS you then can access the these values:
#GET
#Path("/channel_name")
List<Content> getContent(#QueryParam("language")String lang,
#QueryParam("from")Long from,
#QueryParam("to")Long to) {
// your logic
}
Of course you need to take care of exceptions and the repsonse including status codes in this case.
I also work for a TV Broadcaster and the approach we have taken is to post the search criteria through a resource. Much easier to handle and doesn't create an endless path.
Interface :
#POST
#Path("/lookup")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
List<Content> getContent(CriteriaSearch cr);
Implementation :
#Override
#Public
public List<ContentInfo> getContent(CriteriaSearch searchCriteria) {
List<ContentInfo> contentInfos = contentManager.lookupContent(searchCriteria);
...

Generating a HATEOAS client library

Suppose I have a RESTful API for managing orders which uses HAL to facilitate HATEOAS:
GET /orders/2
{
"_links": {
"self": "/orders/2",
"items": "/orders/2/items"
},
"subtotal": 30.0,
"shipped": false
}
I want to write my client (application) using a set of interfaces so that, assuming that implementations of these interfaces are DI-d/built by DI-d factories, etc., I don't really (want to) have to care that they're backed by my RESTful API. As an example (pseudo C#/Java):
public interface Order {
public void addItem(Item item);
public float getSubtotal();
public boolean getShipped();
}
Order order = ...;
Item item = ...;
order.addItem(item);
...(order.getSubtotal())...;
My question is: can I/does it make sense to generate implementations of the Order/Item interface from the API? By this I mean in a manner similar to that offered with C#/web services which export WSDLs.
I've been thinking about implementing OPTIONS for resources such as /orders and /orders/{id} so that I'd effectively have a HATEOAS API for traversing the schema of the API:
GET /orders/* (I'd need a suitable wildcard of course)
{
"_links": {
"addItem": {
"href": "/orders/{id}/items",
"templated": true,
"type": "method"
}
}
}
Of course I could make this part of the _links object returned with any given resource (/orders/2, for instance) but that precludes static code generation.
I'm wondering if there's a sensible way to encapsulate the fact that if a particular link is provided, the related action should be available/performed, otherwise not.
Note: In case it matters, I'm actually working in JavaScript (specifically with AngularJS). However, I'd still like to write my application using a set of conceptual interfaces/contracts.
My question is: can I/does it make sense to generate implementations
of the Order/Item interface from the API? By this I mean in a manner
similar to that offered with C#/web services which export WSDLs.
It partially makes sense. By a simple CRUD API you can map the resources to the entities. By complex applications it does not work, because you map URIs to resources and METHOD URI pairs to operations. So every time if you need an operation not defined by HTTP, you have to create a new resource or at least a new URI for an already existing resource.
Some examples:
transfer money from one account to another: POST /transfer [acc1, acc2, amount, currency] - the transfer does not necessary exist as an entity in your domain logic (don't try that kind of solution in production code unless you want bankruptcy :D)
sending an email to another user: POST /messages [recipient, message]
you can map resources to value objects too: GET /users/123/address
you can use URIs to map reduce a collection: GET /users?name="John"
you can use PUT /users/123 [details] instead of POST /users [details] to create a new user
you can use POST /player/123/xp/increment 10 instead of PUT /player/123/xp [xp+10] to update the experience points of a player
About the WSDL like solutions you can read alot more here: Third Generation Web APIs - Markus Lanthaler.
My personal opinion that it does not worth the effort to build such a system, because it has more drawbacks than advantages.

ServiceStack Routing with ravendb ids

I've an entity with an ID of
public string ID {get;set;}
activities/1
(which comes from RavenDB).
I'm registering the following routes in my ServiceStack AppHost
Routes
.Add<Activity>("/activities")
.Add<Activity("/activities/{id}");
I'm using a backbone app to POST and PUT to my REST Service.
What happens out-of-the-box:
id property is serialized into the json as "activities/1"
id property is encoded into route as "activities%2F1"
ServiceStack gives precedence to the URL based id property, so my string gets the encoded value which is no use to RavenDb directly.
The options I'm aware of:
Change backbone to post to "/activities" and let the JSON Serialiser kick in
Change RavenDb ID generation to use hyphens rather than slashes
Make my Id property parse for the encoded %2F on set and convert to a slash
Both have disadvantages in that I either lose RESTfulness in my API, which is undesirable, or I don't follow RavenDb conventions, which are usually sensible out-of-the-fox. Also, I've a personal preference for having slashes.
So I'm wondering if there are any other options in servicestack that I could use to sort this issue that involve less compromise? Either Serialiser customisation or wildcard routing are in my head....
I have the same problem with ASP.Net WebAPI, so I don't think this is so much a ServiceStack issue, but just a general concern with dealing with Raven style id's on a REST URL.
For example, let's say I query GET: /api/users and return a result like:
[{
Id:"users/1",
Name:"John"
},
{
Id:"users/2",
Name:"Mary"
}]
Now I want to get a specific user. If I follow pure REST approach, the Id would be gathered from this document, and then I would pass it in the id part of the url. The problem here is that this ends up looking like GET: /api/users/users/1 which is not just confusing, but the slash gets in the way of how WebAPI (and ServiceStack) route url parameters to action methods.
The compromise I made was to treat the id as an integer from the URL's perspective only. So the client calls GET: /api/users/1, and I define my method as public User Get(int id).
The cool part is that Raven's session.Load(id) has overloads that take either the full string form, or the integer form, so you don't have to translate most of the time.
If you DO find yourself needing to translate the id, you can use this extension method:
public static string GetStringIdFor<T>(this IDocumentSession session, int id)
{
var c = session.Advanced.DocumentStore.Conventions;
return c.FindFullDocumentKeyFromNonStringIdentifier(id, typeof (T), false);
}
Calling it is simple as session.GetStringIdFor<User>(id). I usually only have to translate manually if I'm doing something with the id other than immediately loading a document.
I understand that by translating the ids like this, that I'm breaking some REST purist conventions, but I think this is reasonable given the circumstances. I'd be interested in any alternative approaches anyone comes up with.
I had this problem when trying out Durandal JS with RavenDB.
My workaround was to change the URL very slightly to get it to work. So in your example:
GET /api/users/users/1
Became
GET /api/users/?id=users/1
From jQuery, this becomes:
var vm = {};
vm.users = [];
$.get("/api/users/?" + $.param( { id: "users/1" })
.done(function(data) {
vm.users = data;
});