HATEOAS API Object Design - api

What is the current best practice on using pragmatic hateoas when a POST object may differ from the GET object of the same resource? For example, would the following be bad API design?
For the resource /families a client may POST a new family and include many "members":[] in the same request.
/members is also a resource
Given a successful POST or GET, the server returns an object that includes a different "family" object to include links:
{
"id": 123,
"name": "The Adams Family",
"_links": {
"members": { "href": "/families/123/members" }
}

I think it would be better to use nested resources in this case e.g. in HAL+JSON:
{
"id": 123,
"name": "The Adams Family",
"_embedded": {
"members": {
"_links": {
"self": {
"href": "/families/123/members"
}
}
}
}
}
I think your solution is okay as well, but you have to define the members link relation in the documentation, so the clients (and their developers) will know that "members" means family members, and not for example members of any collection (e.g. hydra defines a member property for collection items and schema.org defines a members property for organization members).

Related

How to reference a resource in a update-request of a hypermedia api?

I did some research about how REST APIs work and how to link resources via hypermedia. Most of the examples about linking resources is related to the response of the server. But I wonder how to reference to other resources when a certain resource should be updated.
Let´s take the simple resource of a person living at a specific location:
/api/persons/alice
{
"name": "Alice",
"location": {
"id": 1,
"links": {
"self": "/api/locations/1"
}
}
}
Now I want to update the location to another existing location. But how do I represent that?
Would I:
refer to the id of the new location
PUT /api/persons/alice
{
"name": "Alice",
"location": 2
}
refer to the URI of the new location
PUT /api/persons/alice
{
"name": "Alice",
"location": "/api/locations/2"
}
anything else?
HTTP PUT has remote authoring semantics - you should think of the payload as being the new representation of a document, being manipulated by some general purpose HTTP aware document editor.
GET /api/persons/alice HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
{
"name": "Alice",
"location": {
"id": 1,
"links": {
"self": "/api/locations/1"
}
}
}
PUT /api/persons/alice HTTP/1.1
Content-Type: application/json
{
"name": "Alice",
"location": {
"id": 2,
"links": {
"self": "/api/locations/2"
}
}
}
200 OK
The assumption here is that the consumer of your API is familiar with the schema here, and understands the semantics, which fields are optional, which are required, and so on.
(Getting this to work on a long time scale means investing effort in designing your schema well, choosing reasonable defaults, and so on).
Please observe this part of the PUT specification with care:
An origin server SHOULD verify that the PUT representation is consistent with any constraints the server has for the target resource that cannot or will not be changed by the PUT.... When a PUT representation is inconsistent with the target resource, the origin server SHOULD either make them consistent, by transforming the representation or changing the resource configuration...
...
An origin server MUST NOT send a validator header field (Section 7.2), such as an ETag or Last-Modified field, in a successful response to PUT unless the request's representation data was saved without any transformation applied to the body....
In other words, the server doesn't need to "store" the new representation as provided.

What is the correct client side implementation of consuming HAL API Endpoint that returns a list of links

Based on the Richardson Maturity Model some API systems are implemented with Level 3 - Hypermedia API architecture style in mind. As i am concerned about it as it still an Internet Draft (a "work in progress"), I am dealing with one of those systems currently and I am working on creating a client side generic implementation to deal with it.
First things first, I have a basic scenario as the title of the question shown. I am using C#. Consuming a HAL API Endpoint that returns a json like the below and you can see inside CarsApiHeaderModels I have an array of objects that contains a link to each object so i can navigate through:
{
"proberty1": "value1",
"proberty2": "value2",
"CarsApiHeaderModels": [
{
"CarId": "e41b63e6-3678-4f79-92da-aabc00da06b3",
"CarReference": "xxxxx",
"_links": [
{
"Rel": "getCar",
"Href": "api/CarApi/e41b63e6-3678-4f79-92da-aabc00da06b3",
"Title": null,
"IsTemplated": false
},
{
"Rel": "getCar",
"Href": "api/CarApi/7b05bde2-aa55-4400-9343-98ba3287ca03",
"Title": null,
"IsTemplated": false
}
],
"_embedded": null
}
],
"TotalCount": 2,
"_links": [
{
"Rel": "self",
"Href": "api/CarListApi?proberty1=value1&proberty2=value2",
"Title": null,
"IsTemplated": false
}
],
"_embedded": null
}
I wanted to retrieve a List<Car> not a list of links to the car resource's endpoints which have shown under CarsApiHeaderModels but because i am dealing with a HAL compliant API, that's what i am getting.
In the C# client side, what is the efficient way of getting a list of Car objects. Is the right way to iterate through each link and retrieve the object? To be honest that doesn't make sense to me? Also I've went through many discussions and implementations but it seems the topic not mature enough and has a lot of urging between the developers.

REST pattern create, update and delete same endpoint

I have a page where I list the books of a school. The user can update a book, add a new book or delete an existing book. All actions must be saved when the form is submitted.
How can i map a rest API for that? I could take advantage of the endpoints i already have.
UPDATE
PUT /schools/1/books
{
"books": [
{
"id": "1",
"name": "Book 1"
}
]
}
CREATE
POST /schools/1/books
{
"books": [
{
"name": "Book 2"
},
{
"name": "Book 3"
}
]
}
DELETE
DELETE /schools/1/books
{
"books": [
{
"id": 2
}
]
}
But I need everything to run on the same transaction, and wouldn't make sense to submit 3 requests.
I also thought of creating a new endpoint where I would create books that doesn't exists, update books that exists, and remove books that are not present on the request.
So if this school has Book 1 and Book 2, I could update Book 1, create New Book and remove Book 2 with:
PUT /schools/1/batch-books
{
"books": [
{
"id": "1",
"name": "Updated Book 1"
},
{
"name": "New Book"
}
]
}
Do you guys have other options?
I would separate things into different resources:
/books and /books/{id} for books. They gives book details and allow to manage them.
/schools and /schools/{id} for schools. They gives school details and allow to manage them.
/schools/{id}/books to associate books in schools. I mean books that are available within a school. This resource provides methods to manage a list of links to books.
Let me detail the last resource. In fact, this is related to hypermedia. In the following, I'll use JSON-LD but you're free to use other hypermedia tools.
A GET method will return the list of associated books:
GET /schools/1/books
[
{
"#id": "http://api.example.com/books/1895638109"
},
{
"#id": "http://api.example.com/books/8371023509"
}
]
You can notice that you can implement mechanisms to allow to get more details if needed. Leveraging the Prefer header seems to be a great approach (see the link below for more details).
In addition, you could provide the following methods:
POST to add a link to the school. The request payload would be: {"#id": "http://api.example.com/books/1895638109"}. The response should be a 201 status code.
DELETE to delete a specific link from a school. A query parameter could be used to specify which link to remove.
PATCH to allow to do several operations in one call and actually provide some batch processing. You can leverage at this level JSON-PATCH for the request processing. Within the response, you could describe what happens. There is no specification at this level so you're free to use what you want... Here is a sample for the request payload:
PATCH /schools/1/books/
[
{
"op": "add", "value": "http://api.example.com/books/1895638109"
},
{
"op": "remove", "path": "http://api.example.com/books/8371023509"
}
]
Reading the following links could give you some hints on the way to design such use case:
Implementing bulk updates within RESTful services: http://restlet.com/blog/2015/05/18/implementing-bulk-updates-within-restful-services/
On choosing a hypermedia type: http://sookocheff.com/post/api/on-choosing-a-hypermedia-format/
Creating Client-Optimized Resource Representations in APIs: http://www.freshblurbs.com/blog/2015/06/25/api-representations-prefer.html
Hope it helps you,
Thierry

REST Media Type Proliferation

I took a look at this question that seeks to address the issue of REST media-type explosion. One of the suggestions was to have a media-type that describes a collection of anything. So for example, we could have an application/vnd.collection+json which is a collection with well-defined semantics that can hold a list of references to other resources:
{
"size": "3"
"elements": [
{ "href" : "http://my.api.com/resource/1" },
{ "href" : "http://my.api.com/resource/2" },
{ "href" : "http://my.api.com/resource/3" }
]
}
I know an option to alleviate chattiness is to include embedded representations of resources. How would a "generic" media-type for lists accomplish that? Don't the semantics of the list change based on which embedded resource is inside it? This is especially relevant if embedded resources have different processing-rules (which would ideally be conveyed by the media type). Would be alright in this case to allow in-band information that describes the media type of the embedded resource? For example we could have application/vnd.collection+json for both links and embedded resources that do something like this:
{
"size": "3"
"element-content-type": "application/vnd.link+json"
"elements": [
{ "href" : "http://my.api.com/resource/1" },
{ "href" : "http://my.api.com/resource/2" },
{ "href" : "http://my.api.com/resource/3" }
]
}
and if it contains an embedded resource:
{
"size": "3"
"element-content-type": "application/vnd.resource+json"
"elements": [
{
"id": "1"
"name": "Cool Resource"
},
{
"id": "2"
"name": "Awesome Resource"
},
{
"id": "3"
"name": "Super Awesome Resource"
}
]
}
The assumption is that application/vnd.link+json and application/vnd.resource+json have been documented as well.
I thought about this a little bit more, and I think it is actually OK to include the content-type like that. The reason is, we already do this. In HTML the script tag has a type attribute that can be application/javascript or application/vbscript (for example). The provides the browser a hint as to how to process the content of that tag. Similarly, I think the content-type in the above example achieves the same purpose: it tells the client how to process the elements in the collection.
I wanted to update this answer some more. It appears that another way to do this is to use a rel. At least, this is how HAL does it. You can create a namespaced rel with a curie so that you end up resolving the rel to a URL that points to documentation about that resource. This way you have access to the documentation and that should tell you all you need to know about the resource(s).

REST: Link resources with dependency

I'm trying to design a relationship between two different resources with dependency. The scenario is:
Two resources, the first one called "account" and the second one called "person".
In my API the "person" resource is a representation of a person in real world, with name, age, gender, address, telephone, etc. Account is the resource responsible to authenticate a person, like a login.
So the representation of "person" resource looks like below:
{
"id": "7828292",
"name": "Joseph Climber",
"email": "yourmail#email.com",
"gender": "M",
"telephones": {
"main": {
"number": "898987777"
},
"secondary": {
"number": "909099090"
},
"business": {
"number": "937363902"
}
},
"address": {
         "rel": "address",
         "href": "person/{ID}/address"
     }
}
And the representation of "account" resource looks like:
{
"id": "login#email.com",
"tokenAccess": "5E69FAE25F4B4F3E8CC5DE09A8163520",
"link": {
"rel": "person",
"href": "person/{id}"
}
}
My problem is: when I create a new person (POST person) I don't have a way to authenticate the new person, in this case is necessary to create a new account to do this, so this seems a little bit confusing for the API consumers, because the API doesn't express this kind of relationship naturally (basic concept of a good API design).
What is the best way to represent this dependency between account and person resource?
Maybe if someone attempts to POST to /person without an access token, then return a status code 401 Unauthorized with a body something like:
{
"#type": "error",
"description": "You must be authenticated to POST to person. If you do not have an account, then POST to /account to get an access token."
}
I imagine that would be intuitive enough for developers using the API.