My web application requires a REST endpoint GET /products whose semantics is to retrieve a set of products from a product catalogue.
Each product has a set of attributes including an image in PNG format:
[
{
productId: 123,
name: "boat",
image: "\\x89504e470d0a1a0..." <-- PNG retrieved from PostgreSQL bytea
},
{
productId: 456,
name: "helicopter",
image: ...
}
... and many more
]
I believe this approach is not REST compliant because the image's Mime-Type is not explicitly mentioned.
The approach that is closer to the REST spirit would be to include, instead of the binary data, a hyperlink to the image resource
[
{
productId: 123,
name: "boat",
image: {
href: "/product/123/image <-- GET response to this resource has Mime-Type image/png
}
},
{
productId: 456,
name: "helicopter",
image: {
href: "/product/123/image <-- GET response to this resource has Mime-Type image/png
}
}
... and many more
]
But in that case the client would need to GET the product images one-by-one which adds significant overhead to the network (TCP connections) and the database (querying for the images one-by-one).
Is there a best practice for embedding multiple images in a single json response with the correct Mime-Type?
Is there a best practice for embedding multiple images in a single json response with the correct Mime-Type?
It sounds like what you are looking for is the "data" URL Scheme (RFC 2397), which allows you to specify the media type as part of the URL.
data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7
Related
I'm implementing my first REST API, and I have a question about the syntax of the URL endpoints.
I know that I should use these endpoint for get, create, update and delete:
Get list of items
Method: GET, Url: /api/items
Get item by id
Method: GET, Url: /api/items/:id
Add item (new item data in the request body)
Method: POST, Url: /api/items
Modify item (modified item data in the request body)
Method: PUT, Url: /api/items/:id
Delete item
Method: DELETE, Url: /api/items/:id
But lets say the interface of item is
interface item
{
id: string;
name: string;
}
What should be the request url for getting an item by it's name?
I can't use Method: GET, Url: /api/items/:name, because this will match the get-by-id request. So how should I syntax this endpoint?
There is no standard REST URI syntax unless you are doing OData for example. You have perfect freedom designing your own URIs, even /resource/{id} is perfectly valid.
What I like to do is end the URIs of collections with / and use queries for filtering collections. So I would do /api/{version}/items/?name={name} if they have unique names and you expect an item instead of a collection, then I would do it this way: /api/{version}/items/name:{name}. But this is my style.
From client perspective the URI syntax is totally irrelevant, because the server gives the valid URI templates to the client according to the HATEOES constraint. If you thought otherwise, then probably you are building a CRUD API instead of a REST API.
You chould use a filter on the collections endpoint like:
Method: GET, Url: /api/items?name=foo
This filter could return all items which have a foo string in them (depending on how you want to handle wildcards in the search / filter term), e.g. the response could be a collection of items:
{
"data": [
{
"id": "d079d8e9-4d24-4514-b356-78587f6c2ba9",
"name": "foo"
},
{
"id": "7f5e558c-6a7f-4ebe-8f4f-a2d029a803ed",
"name": "foo bar"
}
]
}
If you want the response to return a single resource you could also use the name as identifier and apply the scheme from above using the name, e.g.
Method: GET, Url: /api/items/:name
What is best practice for data synchronization operation between client and server?
We have 2 (or more) resources:
cars -> year, model, engine
toys -> color, brand, weight
And we need to get updated resources from server in case of any updates on them. For example: someone made changes from another client on the same data and we need to transfer those updates to our client application.
Request:
http://api.example.com/sync?data=cars,toys (verb?)
http://api.example.com/synchronizations?data=cars,toys (virtual resource "synchronizations")
Response with mixed data:
status code: 200
{
message: "ok",
data: {
cars: [
{
year: 2015,
model: "Fiat 500"
engine: 0.9
},
{
year: 2004,
model: "Nissan Sunny"
engine: 1.3
}
],
toys: [
{
color: "yellow",
brand: "Bruder"
weight: 2
}
],
}
}
or response with status code 204 if no updates available. In my opinion making separated http calls in not a good solution. What if we have 100 resources (=100 http calls)?
I am not an expert, but one method I have used in the past is to ask for a "signature" of the data, as opposed to always going and getting the data. The signature can be a hash of the data you are looking for. So, flow would be something like:
Get signature hash of the data
http://api.example.com/sync/signature/cars
Which returns the signature hash
Check if the signature is different from the last time you retrieved the data
If the signature is different, go and get the data
http://api.example.com/sync/cars
Have the REST also add the new signature to the data
{
message: "ok",
data: {
cars: [
{
year: 2015,
model: "Fiat 500"
engine: 0.9
},
{
year: 2004,
model: "Nissan Sunny"
engine: 1.3
},
],
signature: "570a90bfbf8c7eab5dc5d4e26832d5b1"
}
}
I am designing a REST API. There's an entity Organization which may have a parent organization and multiple child organizations.
Let's say a user does request GET /organizations/1234.
What should I respond with?
I can use URLs to these other organizations.
{
"data": {
"name": "Microsoft",
"parent_organization": "http://api.myapi.asdfghj/organizations/1220",
"child_organizations": [
"http://api.myapi.asdfghj/organizations/1236",
"http://api.myapi.asdfghj/organizations/1214"
]
}
}
or I can use their ids
{
"data": {
"name": "Microsoft",
"parent_organization": 1220,
"child_organizations": [
1236,
1214
]
}
}
Which one is better?
If it's the one with full URLs, how do I do document that in swagger? Do I just set that as a string, something like the following?
definitions:
Organization:
type: object
properties:
data:
type: object
properties:
name:
type: string
parent_organization:
type: string
format: url
child_organizations:
type: array
items:
type: string
format: url
What about POST /organizations for creating a new user? Should the user specify parent and children as urls too?
I suggest you use urls rather than some ids. The advantage of having actual urls is that you can change them dynamically without worrying about the clients who depend on some base urls and then have to compute the actual urls from ids, etc.
For documentation purpose you can treat urls as strings and explain them like other params.
What is a correct rest way of getting a resource ID by a field, for example a name. Take a look at the following operations:
GET /users/mike-thomas
GET /users/rick-astley
I don't want to use these operations at my API end, instead I want to write an API operation that will get me the ID when submitting a field (name in the case of users) for example:
GET /users/id-by-field
Submitted data:
{
"fullName": "Mike Thomas"
}
Return data:
{
"data": {
"id": "123456789012345678901234"
}
}
What you want is known as an algorithmic URL where the parameters for the algorithm are passed as URL parameters:
GET /users?name="Mike Thomas"
Advantages are that you are using the "root" resource (users) and the search parameters are easily extended without having to change anything in the routing. For example:
GET /users?text="Mike"&year=1962&gender=M
where text would be searched for in more than just the name.
The resultant data would be a list of users and could return more than the identification of those users. Unless fullName uniquely identifies users, that is what you need to allow for anyway. And of course the list could contain a single user if the parameters uniquely identified that user.
{
users: [
{
id: "123456789012345678901234",
fullName: "Mike Thomas",
dateJoined: 19620228
}
, {
id: "234567890123456789012345"
fullName: "Rick Astley",
dateJoined: 19620227
}
]
}
I have a table Article, a table Tag and a joint table to associate a tag to an article.
While creating a new Article, by sending a POST request to /Service.svc/Articles, is it possible to enclose in the JSON object a list of Tag ids to be associated?
Something like:
{
title: "My article title",
text: "The content:",
Tags: [ { id: 1 }, { id: 2 }, { id: 3 } ]
}
If not can I send the list of tags in one request? For example:
/Service.svc/Articles(1)/Tags
[ { id: 1 }, { id: 2 }, { id: 3 } ]
Or do I have to make as many requests as they are tags?
Thank you very much in advance.
You can modify just the links by POST/PUT/DELETE to the $links URL as described here: http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries
The samples there use ATOM/XML, but the respective JSON format is also possible.
To send multiple operations to the server in one request (to save the roundtrips) you can create a batch request as described here:
http://www.odata.org/developers/protocols/batch