I'm writing a REST service which is dealing with SomeKindOfResource stored in a database.
Don't ask me why (don't!) but for some reasons, the corresponding underlying table has a variable number of columns. That's the way it is and I can't change it.
Therefore, when I issue a GET /SomeKindOfResources/{id}, my DTO (later on serialized to JSON) might then contain a variable number of "fields". I know how to handle the dynamic object / serialization parts. My question is more on the philosophy side of things.
Let's say my client wants to know what will be the list of fields returned by a call to GET /SomeKindOfResources/{id} because, for example, that list determines what can be used, later-on, to filter out a list of SomeKindOfResources. Basically, I need something resembling a "GetCapability".
How would you deal with such a scenario in a RESTful way?
If I understand your requirement correctly, you want to return a metadata like response for a specific object (i.e. by Id) that has dynamic fields, so your client knows the field types it will receive when requesting that object.
Just a word of caution: A dynamic DTO isn't RESTful. The point of a DTO is that it is an agreed contract. It shouldn't change and as such there isn't a RESTful rule to handle your use case.
If you were to implement this, these are three possible approaches.
Metadata Route:
Create a new route, in your service, as this scenario isn't covered by the standard ServiceStack MetadataFeature, as it only works with static DTOs. So create something like this:
[Route("/SomeKindOfResources/{Id}/metadata", "GET"]
Then you would want the response to that route to describe the fields to your client. This is where it gets cloudy. The MetaDataFeature uses XSD to describe your standard DTOs, you could write your action to produce an XSD response which would describe your fields, based on your database lookup of available fields. But then will your client know how to parse XSD? As your use isn't standard, and the client can't be expected to handle it in a RESTful way, so you may just want to use a simple response type, like a Dictionary<string,Type>() essentially just returning field name, and underlying type. This will work fine for simple built in types, like string, int, bool etc, but custom class scenarios will be harder to handle, such as List<MySpecialType>.
Pseudo client code:
var fieldMetaData = client.get("/SomeKindOfResources/123/metadata");
var result = client.get("/SomeKingOfResources/123");
Example XSD Metadata Response.
OPTIONS header:
However you may wish to consider using the OPTIONS verb instead of a GET request to another prepended with /metadata, as recommended by RFC2616 ยง9.
This method allows the client to determine the options and/or requirements associated with a resource ... without implying a resource action or initiating a resource retrieval.
Pseudo client code:
var fieldMetaData = client.options("/SomeKindOfResources/123");
var result = client.get("/SomeKindOfResources/123");
But remember OPTIONS in REST is typically used for setting up CORS.
ServiceStack JSON __type response:
When ServiceStack returns JSON, you can tell the ServiceStack.Text serializer to include the return type information in a property call __type. Although this may not be easy for your clients to interpret, and it also applies globally to all JSON responses, so wouldn't be limited to just that action. In your configure method add:
JsConfig.IncludeTypeInfo = true;
Pseudo client code:
var result = client.get("/SomeKingOfResources/123");
var typeInformation = result.__type;
Related
From my client application I make a POST call to a \validate end-point. This call is made to execute the controller on the server side and not to create any resource. In response, server can provide one of the two totally unrelated JSON objects. From the client, how do I know which of the two types I should use during deserialization? What is the clean way to do this?
There are multiple ways to do it.
Add some header to the http response to determine body type. Client should check header and use corresponding deserializer. This is a typical approach for webhooks API where you have single endpoint to process different event type. As an example, you could check AWS SNS API that uses x-amz-sns-message-type header to define response type.
As an alternative you could use special body format with some type field and payload that depends on this type.
{
"type: "Type",
"paylod": {
...
}
}
But from my opinion this approach is much harder to handle for the client and would required 2-step deserialization process.
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS. For example:
GET city/documents:
[{
id: 1,
city: {
self: 'http://service.com/cities?filter=id==1'
},
document: { ... }
...
}, {
id: 2,
city: {
self: 'http://service.com/cities?filter=id==2'
},
document: { ... }
...
}]
FYI, the query parameter uses the FIQL syntax to define the filters.
Now, if the client was to fetch the city details for each document (to show on UI), it will probably need N additional calls. However in my case, the /cities API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS? I've read about the templates but not sure how should the template look like and how would client consume it?
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS.
Yes. Less true in a world with Server-Push, where the server can proactively provide multiple resources in response to a query. If you imagine asking for a web page, and getting the html, and then also the images and the java script resources too, then you've got the right sort of idea.
API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS?
Yes.
Let's walk through it carefully. What you've done here is introduced a new resource, with identifier /cities?filter=id=in=(1,2). You might have another resource /cities?filter=id=in=(1,20) and another resource /cities?filter=id=in=(1,2000). In your implementation, these might be a "single endpoint" that extracts parameters from the identifier and uses them to generate the correct representation.
So what you get is something like a data transfer object - a large grained resource fetched in a single go.
I've read about the templates but not sure how should the template look like and how would client consume it?
The simplest example, which you have likely seen already, is a web form. You allow the client to provide the start and end elements, and the form processing takes that information and creates the specified URI from it.
/filtered-cities?start=1&end=2000
So the client needs to understand what the form is for, and how to identify the semantics of the different elements in the form. The agent needs to understand the processing rules that transfer the form data into the URI.
URI Templates are the same basic idea; they give you a domain agnostic language with which to describe where the parameters go in a resource identifier. The basic pattern is the same - there needs to be agreement about the semantics of the parameters, the server provides a URI, the client provides a parameter map, and the generic code can take care of the merge
uri = template.apply(parameterMap)
URI Templates aren't quite as powerful as forms; with a form, you can introduce a default value for a parameter, but there is no analogous capability in URI templates.
HAL-Forms may give you a better sense of how a form based approach might work in JSON.
I have a resource which basically represents a number. I have two possible updates for this number: Set the number to a specific value or add a value to it. Now I'm confused if I can use the query string part of the URL to specify the desired behavior.
Something like this:
/resource/{id}/?mode=add
/resource/{id}/?mode=set
Or is there an alternative way two represent to update strategies for a rest resource?
An Alternative would be to extend the request body with this information but this since strange, since the request data should contain the data and not "meta information" for the request itself - as far as I understand REST apis.
The project is an ordinary angularjs (client) and java (server) project.
I'm designing a REST api, following best practices, including a form of hypermedia/hateoas. I'm using jsonapi for the design guidelines, which seems to be pretty complete.
Currently, I have a need for:
combining 2 resources in a response (a Resource A and a related Resource B). I do this using the Compound Documents - structure as specified in jsonapi. Or also commonly known as resource expansion
formatting the result of 1. in a specialized way so it can be readily consumed by a specialized client that expects said formatting.
My problem is with 2. How do I correctly represent this in a REST-way? It seems I may need a separate endpoint, but that wouldn't be 'RESTy', since that implies a separate resource, while it's just a transformation of the output of the same resource.
Any references on how to do this?
You could use a header or a query param to handle this.
When the client needs specific formatting, they could add an additional header to the request something like Format:Indented or something like http:\\myapp.com\resouces\myresource?format=indented
Or if the server is formatting and wants the client to know that the response is pre-formatted, the server could add a Format response header to notify the client that response is formatted.
We have a model that looks like this
Login <- Email Addresses <- Person -> Teen
And a stored procedure which takes some properties from teen, some from person, and some from Login, and creates a new teen, returning a person entity.
Looking from a classic RPC perspective, this is easy...just expose a method InsertTeen and have it call the stored procedure.
I've been trying to wrap my head around the RESTful idea of having URLs as my resources (nouns), and the only actions being HTTP actions (verbs). Obviously, a URL like /api/InsertTeen is not RESTful at all.
But here I'm not dealing with any particular resource.
The only thing I can thing of here would be to expose a resource like insertTeenRequest.
Are there any other ideas of how to do this? Am I being too much of a "zealot"?
If you want to be really RESTful, you should use several requests to your API in this case. For example first you create Teen with POST to /api/teens/, then create Person with POST to /api/persons/ and so on.
Pretty new to REST myself, but my thinking is that here you would use a "POST" with the body of the request containing the data needed to create a 'Teen', in whatever format you are using, usually JSON or XML. Here, I'm not sure whether you treat Teens as Persons with additional properties, or a Teen is modeled as an entity itself:
<person login="abc" email="abc#foo.com">
<person-property-1>value1</person-property-1>
<person-property-2>value2</person-property-2>
<teen>
<teen-property-1>value3</teen-property-1>
<teen-property-2>value4</teen-property-2>
</teen>
</person>
or
<teen login="abc" email="abc#foo.com">
<person-property-1>value1</person-property-1>
<person-property-2>value2</person-property-2>
<teen-property-1>value3</teen-property-1>
<teen-property-2>value4</teen-property-2>
</teen>
Regarding the URI, I believe the segments should be nouns rather than verbs since the URI is supposed to address a resource, so /api/teens rather than /api/InsertTeen.
/api/teens with an HTTP GET would return a list of all Teens, and /api/teens with an HTTP POST would insert a new Teen. To round out the CRUD operations, /api/teens/{id} using HTTP GET would return a specific Teen, /api/teens/{id} with an HTTP PUT would update a Teen using the values passed in the request body, and /api/teens/{id} called with HTTP DELETE would delete the specified Teen.
Edit
Read over your question again, and I may have misunderstood. If you aren't treating 'teens' as a resource, but only 'people', then I would consider /api/people with an HTTP POST, and depending on the values passed in the body of the request, do whatever is appropriate to store that 'person'. So, if the request contained 'teen' values, call your stored procedure that creates a 'Teen' and returns a 'Person'.
HTH