Question

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?

Was it helpful?

Solution

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top