HAL+JSON hypermedia type not a media type for REST? - api

Can the HAL+JSON hypermedia type be used in a way that creates a RESTful service?
From what I have read, the client of a RESTful API should not need to treat different resources with special cases. The media type should instead be used to describe what resources are expected to look like.
The HAL spec gives this example:
GET /orders
{
...
"shippedToday": 20,
...
}
```
As a client of this sample HAL+JSON-serving API, I seem to need to know that an "order" has an attribute of shippedToday. That seems to go against the constraint that the client should not need to understand the representation's syntax.
This is not a critique of HAL. The question is to help my (and others') understanding of RESTful API design.

Can the HAL+JSON hypermedia type be used in a way that creates a RESTful service?
Yes, definitely.
The API should have a billboard URL, which in your case could be /.
This is the entry point from which humans and ideally even machines can start to discover your API.
According to the HAL specification a resources representation contains an optional property called "_links" which is described here:
It is an object whose property names are link relation types (as
defined by RFC5988) and values are either a Link Object or an array
of Link Objects.
So these links represent the hypermedia part of your API. The relations can be IANA-registered relations or you can use your own extension relations.
Relations should not be ambiguous. Their names should be unique. That's why it is recommended to use URIs from your own domain as names for your own relations. These URIs identify a resource that represents the relation and contains an API documentation, a human or machine readable documentation of your relation.
In your case this would be a relation that describes the state transition to the /orders resource. This should also include a description and explanation of the response and therefore document that e.g. the /orders resource represents a list of orders and has a property called "shippedToday" with a value of type number.
Here is an example response for a GET / HTTP/1.1 request:
HTTP/1.1 200 OK
Content-Type: application/hal+json
{
"_links": {
"self": { "href": "/" },
"http://yourdomain.com/docs/rels/orders": { "href": "/orders" },
}
}
Under http://yourdomain.com/docs/rels/orders there should be the API docs.

Related

Having issues with documenting the dynamic keyword in C# ASP.NET Core

We utilize Pagination, and we have a handy little class that helps us, some of it looks like this:
public class PagedResponse<T>
{
public PagedResponse(HttpRequest request, IQueryable<dynamic> queryable,
string maxPageSizeKey, dynamic options, int pageNumber, int pageSize)
{
//code
}
public dynamic Data { get; set; }
At some point, we execute this and assign it to Data:
List<dynamic> dataPage = queryable
.Skip(skip)
.Take(take)
.ToList();
Because this class utilizes the dynamic type, here is what Swagger generates (imagine the type we pass to our PagedResponse class is Foo):
{
"PageNumber": 0,
"PageSize": 0,
"MaxPageSizeAllowed": 0,
"FirstPage": "string",
"NextPage": "string",
"LastPage": "string",
"TotalPages": 0,
"TotalRecords": 0,
"Data": {} <---- Here we want it to describe Foo
}
I also notice that when you click on 'schema' it gives it the concatenated name FooPagedResponse.
The fact that swagger doesn't give any information about Data is becoming a sticking point for our React developers who utilize some utility to grab schemas.
Now, here's the thing, if you replaced anywhere that I used dynamic with T, swagger, of course, would be happy. But that's no solution, because we have to use dynamic.
Why? OdataQueryOptions and the possibility of using the odata $select command.
Before we are executing the queryable (the .ToList above), we are doing something like this (as well as other odata commands):
if (options.SelectExpand != null)
{
queryable = options.SelectExpand.ApplyTo(queryable, settings) as IQueryable<dynamic>;
}
(options was the "dynamic options" passed to the constructor, this is the ODataQueryOptions)
Once you apply a $select you can no longer assign the .ToList to List<T> it has to be List<dynamic>, I get an exception otherwise about not being able to convert types.
I can't take away the ability to $select just to get proper documentation. What can I do here?
While this is not a direct answer to the original post, there is a lot to unpack here, too much for a simple comment.
Firstly, the original question is essentially: How to customise the swagger documentation when returning dynamic typed responses
To respond to this directly would require the post to include the swagger configuration as well as an example of the implementation, not just the type.
The general mechanism for extending Swagger docs is by implementing IDocumentFilter or IOpertationFilter so have a read over these resources:
IOperationFilter and IDocumentFilter in ASP.NET Core
Is there a way to get Swashbuckle to add OData parameters
Because you are using a dynamic typed data response the documentation tools cannot determine the expected type so you would need to provide that information, if it is available, in another way, there are many different addons and code examples out there, but I haven't come across an implementation like this, so can't provide a specific example. Most of OData configuration is derived through reflection, so if you have obfuscated the specific implementation through dynamic most of the OData tools and inner workings will simply fail.
Now, here's the thing, if you replaced anywhere that I used dynamic with T, swagger, of course, would be happy. But that's no solution, because we have to use dynamic.
The only reason that your code requires you to use a dynamic typed response is because it has been written in a way as to require that. This is a constraint that you have enforced on the code, it has nothing to do with EF, OData or any other constraints outside of your code. When a $select operation is applied to project a query result, we are not actually changing the shape of the data at all, we are simply omitting non-specified columns, in a practical sense their values will be null.
OData is very specific about this concept of projection, to simplify the processing at both the server and client ends, a $select (or $expand) query option can not modify the schema at all, it only provides a mask that is applied to the schema. It is perfectly valid to deserialise a response from a $select projection into the base type, however the missing fields will not be initialized.
It is not always practical to process the projected response in the base type of the request, so many clients, especially any late-bound languages will receive the data in the same shape that it was transferred over the wire in.
While you could go deep into customising the swagger output, this post smells strongly like an XY problem, OData has a built in mechanism for paging IQueryable<T> responses OOTB, yes the response is different to the PagedResponse<T> class that you are using, it is more than adequate for typical data paging scenarios and it's implementation is very similar to your custom implementation.
If you use the in-built paging mechanism in OData, using the $skip and $top query options, then your code implementation will be simpler and the swagger documentation would be correct.
You have admitted to being new to OData, so before blindly customising standard endpoints it is a valuable experience to first gain an understanding of the default behaviours and see if you can re-align your requirements with the standards.
A key driving reason to adopt OData in the first place is to be standards compliant, so that clients can make calls against your API following standard conventions and code generation tools can create reliable client-side interfaces. Once you start customising the in-built behaviours you must then customise the documentation or $metadata if you want to maintain compatibility with those types of processes.
By default, when a $top query option is provided, the response will include a link to get the next page of results. If you have not enabled the count to be provided automatically, you can use the $count=true query option to enable the overall count to be provided in the output.
The key difference between your custom implementation and the OData implementation is that the client is responsible for managing or maintaining the list of Page Numbers and translating them into $top and $skip values.
This is a deliberate push from the OData team to support virtual paging or load on demand scrolling. The expectation is that the user might get to the bottom of a list and either click to see more, or by virtue of reaching the end of the current list more records would be dynamically added to the previous set, becoming a delayed load yet continuous list.
To select the 3rd page, if the page size is 5, with both a projection and a filter we could use this url:
~/OData/Companies?$top=5&$skip=10&$select=CompanyName,TradingName&$filter=contains(CompanyName,'Bu')&$count=true
{
"#odata.context": "~/odata/$metadata#Companies(CompanyName,TradingName)",
"#odata.count": 12,
"value": [
{
"CompanyName": "BROWERS BULBS",
"TradingName": "Browers Bulbs"
},
{
"CompanyName": "BUSHY FLOWERS",
"TradingName": "Bushy Flowers"
}
],
"#odata.nextLink": "~/OData/Companies?$top=5&$skip=10&$select=CompanyName%2CTradingName&$filter=contains%28CompanyName%2C%27Bu%27%29"
}
This table has thousands of rows and over 30 columns, way to much to show here, so its great that I can demonstrate both $select and $filter operations.
What is interesting here is that this response represents the last page, the client code should be able to interpret this easily because the number of rows returned was less than the page count, but also because the total number of rows that match the filter criteria was 12, so 2 rows on page 3 when paging by 5 was expected.
This is still enough information on the client side to build out links to the specific individual pages but greatly reduces the processing on the server side and the repetitive content returned in the custom implementation. In other words the exact response from the custom paging implementation can easily be created from the standard response if you had a legacy need for that structure.
Don't reinvent the wheel, just realign it.
Anthony J. D'Angelo

REST standards for posting data

I am using Ember.
The model being posted by ember is
{
"user": {
"firstName": "Vivek",
"lastName": "Muthal"
}
}
Ember had wrapped the data into "user" object.
But the service I have written accepts only {"firstName":"string","lastName":"string"}.
So my question is does REST standards specifies to send / receive data in wrapped Object only?
Any references please so I can change the service accordingly.
Or else I will modify the ember to use my current service as it is. Thanks.
I suppose that the resource is User, so the JSON should represent a User. Lets say you have this URI schema.
GET /host/users/{userId}
PUT /host/users/{userId}
POST /host/users
When we do GET we expect a JSON that represents A User
{
"firstName": "Vivek",
"lastName": "Muthal"
}
There is no need to specify the resource name because we already mentioned that in our GET request, The same for POST, there is no need to mention the resource name in the request body because it is specified in the request URI.So no there, is no need for user key.
No. There is no predefined format for the data you send in the body of your HTTP requests. Well ok, the HTTP RFCs do put technical limits on the data you send, but the formatting is entirely up to you.
As such, you can format your data however you want. You just need to represent the resource. You do need to consider if the JSON for a user should clearly mark the object as a 'user' or not, I would consider it mostly redundant to do so.
REST defines an uniform interface constraint. This constraint states that you have to use standards solutions to create an uniform interface between the service and the clients. This way the clients will be decoupled by the implementation details of the service, because the standards we use are not maintained by the server...
To make it short you can use any standard MIME type, or define a vendor specific MIME type. I strongly suggest you to use an existing hypermedia format like JSON-LD+Hydra or HAL. I guess this kind of serialization is an ember specific thing.

Why providing pagination information in API response?

We are now designing our RESTful API and I have a question for how to expose the pagination information.
It seems some famous services like Github or Firefox Market Place having something like below in their API:
{
"meta": {
"limit": 3,
"next": "/api/v1/apps/category/?limit=3&offset=6",
"offset": 3,
"previous": "/api/v1/apps/category/?limit=3&offset=0",
"total_count": 16
}
}
My question is:
Why should the server give the complete next/previous url in the response?
It seem to me that the client is making the first request. So it knows what parameters it used to call (offset/limit/api version). It is easy for the client to figure out what is the next/previous url to call. Why bother to calculate the redundant urls and give it to the client?
It's RESTful! That is specifically part of HATEOAS, or Hypermedia as the Engine of Application State.
Except for simple fixed entry points to the application, a client does not assume that any particular action is available for any particular resources beyond those described in representations previously received from the server.
and:
[HATEOAS] is a constraint of the REST application architecture that distinguishes it from most other network application architectures. The principle is that a client interacts with a network application entirely through hypermedia provided dynamically by application servers. A REST client needs no prior knowledge about how to interact with any particular application or server beyond a generic understanding of hypermedia.
...
A REST client enters a REST application through a simple fixed URL. All future actions the client may take are discovered within resource representations returned from the server.
(Emphasis added)
It seem to me that the client is making the first request. So it knows what parameters it used to call (offset/limit/api version).
Yes, the client makes the first request, but that doesn't mean it knows anything about URL discovery, pagination, limit/offset parameters, etc.

Implementing versioning a RESTful API with WCF or ASP.Net Web Api

Assume i've read a lot about versioning a restful api, and I decided to not version the the service through the uri, but using mediatypes (format and schema in the request accept header):
What would be the best way to implement a wcf service or a web api service to serve requests defining the requested resource in the uri, the format (eg. application/json) and the schema/version (eg player-v2) in the accept header?
WCF allows me to route based on the uri, but not based on headers. So I cannot route properly.
Web Api allows me to define custom mediatypeformatters, routing for the requested format, but not the schema (eg. return type PlayerV1 or PlayerV2).
I would like to implement a service(either with WCF or Web Api) which, for this request (Pseudo code):
api.myservice.com/players/123 Accept format=application/json; schema=player-v1
returns a PlayerV1 entity, in json format
and for this request:
api.myservice.com/players/123 Accept format=application/json; schema=player-v2
returns a PlayerV2 entity, in json format.
Any tips on how to implement this?
EDIT: To clarify why I want to use content negotiation to deal with versions, see here: REST API Design: Put the “Type” in “Content-Type”.
What you are bringing here does not look to me as versioning but it is is more of content negotiation. Accept header expresses wishes of the client on the format of the resource. Server should grant the wishes or return 406. So if we need more of a concept of Contract (although Web API unline RPC does not define one) then using resource is more solid.
The best practices for versioning have yet to be discussed fully but most REST enthusiast believe using the version in the URL is the way to go (e.g. http://server/api/1.0.3/...). This also makes more sense to me since in your approach using content negotiation server has to keep backward compatibility and I can only imagine the code at the server will get more and more complex. With using URL approach, you can make a clean break: old clients can happily use previous while new clients can enjoy the benefits of new API.
UPDATE
OK, now the question has changed to "Implementing content-negotiation in a RESTful AP".
Type 1: Controller-oblivious
Basically, if content negotiation involves only the format of the resource, implementing or using the right media type formatter is enough. For example, if content negotiation involves returning JSON or XML. In these cases, controller is oblivious to content negotiations.
Type 2: Controller-aware
Controller needs to be aware of the request negotiation. In this case, parameters from the request needs to be extracted from the request and passed in as parameter. For example, let's imagine this action on a controller:
public Player Get(string schemaVersion)
{
...
}
In this case, I would use classic MVC style value providers (See Brad Wilson's post on ValueProviders - this is on MVC but Web API's value provider looks similar):
public Player Get([ValueProvider(typeof(RequestHeadersSchemaValueProviderFactory))]string schemaVersion)
{
...
}

Domain Driven Design - External Data API as Respository or Service

In a blog application developed using domain driven design a 'Post' entity has a related collection of tag entities.
On creating the post (e.g populating the object from the UI) i would like to call a third party API via REST which takes the content of the post and extracts semantic tags (link text) for association.
Main Question : What is the best way to design this...
Is it best designed so that the Post entity would call a domain service such as PostServices.GetTags(Postcontent) passing its content and retrieving back a list of tags.?
** PostServices.GetTags would then inteface with the REST API via a further wrapper class.
Or should the third party API be wrapped as a repository?
Should the function Post.GenerateTags(), should not exist within the domain entity at all?
Further questions :
1 : I have also read that it is not good practice to have a domain entity converse with a domain service. Is this true?
2 : Is it ok to get a reference to the PostServices domain service via a factory creation method. e.g...
IPostService PostService = ServiceUtil.GetPostService();
return PostService.GetTags(Post.content);
3 : Is it acceptable to have the domain service coupled to a third party api?
4 : Should the domain entity simply just know how to deal with the tags received via the application layer which has called the REST API.
Slowly trying to get my head around DDD, however I can't seem to find any examples of how to implement this sort of thing.
In a Blog application, a Post is an Entity and a Tag is a value object. A Tag hasn't got identity. You should have:
PostsRepository
Post (Entity)
Tag (value object)
A Post has got a list of tags.
Questions:
1 : I have also read that it is not good practice to have a domain entity converse with a domain service. Is this true?
Yes, itsn't a good practice. You entity hasn't want to be coupled with a domain service. If you do that, then you couldn't reuse them later. Did you have consider to fire a domain event. You can tell your service domain do something fire domain events.
2. : Is it ok to get a reference to the PostServices domain service via a factory creation method. e.g..IPostService PostService = ServiceUtil.GetPostService(); return PostService.GetTags(Post.content);
Yes, it's possible. A factory method could return an abstract class or an interface. This is a good Software Design Principle "code to an interface not to an implementation". If you do this, you'll be able to change your implementation later and you won't have to change yout client code.
3 : Is it acceptable to have the domain service coupled to a third party api?
I don't recommend you this, but it is acceptable.
Sorry, I don't understand question 4.
Look this link. I hope it help you.
https://stackoverflow.com/questions/901462/ddd-where-is-it-most-appropriate-to-get-a-list-of-value-objects/901562#901562