Supporting multiple languages in a REST API - rest

I have a collection of cities for which I'm creating a REST API (my first REST API). Each city has a number of language independent things, such as founding date and population count. Cities also have things that depend on the language, such as the title and a short description. Internally the city documents have this format:
{
"population": 9042,
"name": {
"en": "Berlin",
"nl": "Berlijn",
// ...
},
// ...
}
The users of my API always want to view the city info for a specific language only, and get back something like:
{
"population": 9042,
"name": Berlin,
// ...
}
I've made these accessible via /cities/:id/:language_code, for instance cities/123/en. Now I want to implement listing of cities: GET /cities. There the requested language is also needed. Since this would result in /cities/:language_code, I'm getting the impression putting this at the end of the url is not a good idea, and suspect I'll be better off with /en/cities/...whatever....
How is this typically done in REST APIs? Any big, nicely implemented, API out there that is a good example?

REST API's are based upon HTTP protocol, so they can use the headers, that are traditionaly used to defined the prefered locale.
So I would use a Accept-Language parameter for this.
# Request
GET /cities/.... HTTP/1.1
Host: www.example.org
Accept-Language: en,en-US,fr;q=0.6
Would give :
{
"population": 9042,
"name": Berlin,
// ...
}

It depends on your clients. If the clients are applications, then #Orabîg's answer is 100% correct. If your clients are web browers, though, you should track language as a user preference. The reason is that a user might be using a non-personal machine where the browser is set to a different language, and they may not know how to or be able to change that setting. Rather than forcing them to use an unfamiliar language, you build the preference into your API.
In that case, I would start with the language provided in Accept-Language until the user either identified themself. Once they are passing some identifying token in a header with each request, use that to figure out what language responses should be in.

Just to mention the related article of W3C about using headers for locale determination (not only language that seems be the original case of the question)
The HTTP Accept-Language header was originally only intended to specify the user's language. However, since many applications need to know the locale of the user, common practice has used Accept-Language to determine this information. It is not a good idea to use the HTTP Accept-Language header alone to determine the locale of the user. If you use Accept-Language exclusively, you may handcuff the user into a set of choices not to his liking.
For a first contact, using the Accept-Language value to infer regional settings may be a good starting point, but be sure to allow them to change the language as needed and specify their cultural settings more exactly if necessary. Store the results in a database or a cookie for later visits.
Some of the potential issues include the following:
Many users never change the defaults for Accept-Language. They are
set when the user agent is installed. Unless they are multilingual or
have some other reason to adjust language preferences they may not
even know such settings exist. Hence, the user may not have ever
ratified the Accept-Language setting.
A user agent may send a request
that specifies only a language and not a region, for example you may
not get a header with de-DE, de-CH or de-AT to indicate German as
spoken in Germany, Switzerland or Austria, respectively. On the other
hand, you might only get de indicating a preference for German. If
you were planning to use the region to decide what currency to use
you are now in a bind. Your particular circumstances might allow you
to make assumptions such as "Germany has 83 million people,
Switzerland has 7 million but only 63% speak German, Austria has 8
million, so this user probably uses the Euro. If we're wrong we'll
only offend 4.6% of our German speaking customers or just over 4
million people." Feel free to make such an assumption, if you can
accept the risk. Its a lot simpler to ask the user for more
information. Also, the math gets more difficult for Spanish or
English, for instance.
People borrow machines from friends, they rent
them from internet cafes. In these cases the inferred locale may be
inappropriate, and care should be taken to allow the user to select
the appropriate language and locale from whatever page they are
looking at.
Full article: Accept-Language used for locale setting

Related

What is the "Restful" way to command a server?

I have a REST endpoint to create an application configuration as such
POST /applications
With a body
{
"appName" : "my-new-app"
}
I returns a newly created application configuration:
{
"appName": "my-new-app",
"appId": "2ed17ff700664dad9bb32e400d39dc68",
"apiKey": "$2a$10$XVDH9F3Ix4lx2LdxeJ4ZOe7H.bw/Me5qAmaIGF.95lUgkerfTG7NW",
"masterKey": "$2a$10$XVDH9F3Ix4lx2LdxeJ4ZOeSZLR1hVSXk2We/DqQahyOFFY6nOfbHS",
"dateCreated": "2021-03-28T11:00:07.340+00:00",
"dateUpdated": "2021-03-28T11:00:07.340+00:00"
}
Note: The keys are auto-generated in the server and not passed from the client.
My question here is, what's the RESTful way to command the server to reset the keys for example:
PUT /applications/my-new-app/update_keys is not noun-based and thus, not restful, also passing a command as query parameter does not also seem to be restful since this is not a GET method rather it's a PUT (update) method.
Here's one way to send a command that is as much as possible RESTful:
Endpoint:
POST /application/:appName/actions
Example Payload:
{
"actions" : [
{
"action" : "name_of_command",
"arguments" : {
"arg1" : "param1"
}
},
{
"action" : "reset_keys",
"arguments" : {
}
}
]
}
Actions would be nouns that are part of the endpoint, and the server will process actions that are submitted (or posted) within the endpoint. And an array of actions would be best suited to allow multiple actions to be sent. And each action having arguments would also be desirable for future actions that would need arguments.
what's the RESTful way to command the server to reset the keys for example:
How would you do it with a web site?
You would be looking at some web page like /www/applications/my-new-app; within the data or the metadata you would find a link. Following that link would bring you to a form; the form would have input controls describing what fields you need to provide to send the message, in addition to any "hidden" inputs. When you click the submit button, your user agent would collect your inputs, construct from them the appropriate message body, then use the form metadata to determine what request method and uri to use.
The client never has to guess what URI to use, because the server is providing links to guide the way.
Hypertext is at the heart of the uniform interface
REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.
Because the server is providing the URI for each of the links, you've got some freedom ot choose which resource "handles" which message.
One interesting way to resolve this to look at HTTP's rules for cache invalidation. The short version is that successful unsafe requests (PATCH/POST/PUT) invalidate the representations of the target-uri.
In other words, we take advantage of cache-invalidation by sending the command to the resource that we are trying to change.
So, assuming that retrieving the representation of the app occurred via a request like:
GET /applications/my-new-app HTTP/x.y
Then we would ask the server to change that resource by sending a request with that same target-uri. Something analogous to:
POST /applications/my-new-app HTTP/x.y
Content-Type: text/plain
Please rotate the keys
Form submissions on the web are usually a representation of key/value pairs, so a more likely spelling would be:
POST /applications/my-new-app HTTP/x.y
Content-Type: applications/x-www-form-urlencoded
action=Please%20rotate%20the%20keys
Your form that describes this request my have an "action" input control, that accepts text from the client, or more likely in this case action would be a hidden control with a pre-defined value.
Note: if we have multiple actions that should invalidate the /applications/my-new-app representations, we would probably use POST for all of them, and resolve the ambiguity at the server based on the request-body (if our routing framework gives us the degree of control we need, we can use that - but more common would be to have a single POST handler for each Content-Type, and parse the request body "by hand".
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Fielding 2009
PUT /applications/my-new-app/update_keys is not noun-based and thus, not restful,
That's not true: REST doesn't care what spelling conventions you use for your resource identifiers. For example
https://www.merriam-webster.com/dictionary/get
https://www.merriam-webster.com/dictionary/post
https://www.merriam-webster.com/dictionary/put
https://www.merriam-webster.com/dictionary/update
These all work fine, just like every other resource on the web.
You absolutely can design your resource model so that editing the update_keys document also modifies the my-new-app document.
The potential difficulty is that general purpose components are not going to know what is going on. HTTP PUT means "update the representation of the target resource", and every general purpose component knows that; the origin server is allowed to modify other resources as a consequence of the changes to the "update-keys" resource.
But we don't have a great language for communicating the general purpose components all of the side effects that may have happened. Without some special magic, previously cached copies of my-new-app, with the original, unrotated, keys, will be left lying around. So the client may be left with a stale copy of the document that describes the app.
(An example of "some special magic" would be Linked Cache Invalidation, which affords describing caching relationships between resources using web linking. Unforunately, LCI has not been adopted as a standard, and you won't find the described link relations in the IANA registry.)

REST endpoint: how to proper design an action on a resource?

I have the resource /contracts with the following structure:
{
name: "Contract name",
signedAt: 123213231,
// etc.
}
While basic CRUD operations are well clear (GET /contracts, GET /contracts/{id}, POST /contracts, etc.) some doubts come when I have to do some concrete actions on the resource.
One of these actions is the following:
sign: means the contract is signed, so the signedAt date will need to be updated with the moment (date-time) the contract was signed.
So far I've been thinking about these different approaches:
PATCH-ing the resource
This approach will mean having the following endpoint method:
PATCH /contracts/{id}
and just posting the signedAt date { signedAt: 123213231 } meaning that after this the contract will be signed.
What I don't like about this approach is that the signature date comes from the client, I was thinking that having this date initialized on the backend side whenever a contract is signed could be better and more consistent.
Totally discarded, as the signedAt date should be set on the server
side exactly at the moment the sign is done.
POST-ing a new resource
This approach will mean having the signature action as a resource:
POST /contracts/{id}/sign
with an empty body in this case as we don't need to pass anything else so, once it is posted, the backend side would be the responsible for having the signature date initialized.
POST-ing the resource using 'action'
Similar to the previous approach, in this case I would use a query parameter called action on the contract resource:
POST /contracts/{idContract}?action=sign
also with an empty body where ?action=sign. Like in the previous approach, once posted the backend side would be the responsible for having the signature date initialized.
Questions
What would be the proper way to have this designed at a REST API level?
Is any of the approaches above close to a good design or not?
Would I need to modify any of the approaches?
Is there any better alternative?
I have designed a few rest APIs myself but I am not a restful evangelist so my answer might not be the best. I would suggest some of the following:
Create a custom converter for date values in your rest service that accepts date AND other specific fields. If you checkGoogle reporting APIs for example they allow you to use specific date range and also CURRENT_WEEK, CURRENT_MONTH etc. So you can add such specific value and use it. For example PATCH signedAt=CURRENT_DATE and the API handles that properly.
Add a boolean signed field to the resource. Do a POST or PATCH with signed=true. This way you will be able to eventually query only signed resources easily ;) Also it might be the case that people care only about if it is signed than when it was signed
I wouldn't use ?action=sign or /contracts/{id}/sign because these are not RESTFUL and even if you do use GET and POST you would use them in a way to create a workaround in order to implement actions in your design which shouldn't have actions
just posting the signedAt date { signedAt: 123213231 } meaning that after this the contract will be signed.
On HTTP Patch
The set of changes is represented in a format called a "patch document" identified by a media type.
Rather than rolling your own bespoke media type, you might want to consider whether one of the standard formats is suitable.
For example: JSON Patch.
Content-Type: application/json-patch+json
[ { "op": "replace", "path": "signedAt", "value": 123213231 }
JSON Merge Patch is another reasonable option
Content-Type: application/merge-patch+json
{ signedAt: 123213231 }
From what I can see, the primary difference is that JSON Patch provides a test operation which gives you finer grain control than simply relying upon validators
But you are absolutely right - PATCH gives the client code authority to specify the time value. If that's not appropriate for your use case, then PATCH is the wrong tool in the box.
POST /contracts/{id}/sign
POST /contracts/{idContract}?action=sign
As far as REST/HTTP are concerned, these two choices are equivalent -- you are updating the state of one resource by sending an unsafe request to a different resource. There are some mild differences in how these spellings act when resolving references, but as request-targets, it doesn't make a difference to the client.
An option that you seem to have overlooked:
POST /contracts/{id}
action=sign
This has the advantage that, when successful, you get cache invalidation for free.
In a hypermedia API, the flow might go something like this: the client would GET the resource; because the resource hasn't been signed yet, the representation could include a form, with a "sign" button on it. The action on the form would be /contracts/{id}. The consumer "signs" the contract by submitting the form -- the agent gathers up the information described by the form, encodes it into the request body, and then posts the request to the server. The server responds success, and the client's cache knows to invalidate the previously fetched copy of the resource.

Facebook Graph API Non English Search Queries

I've been trying to use facebook graph api public search.
It works just fine for english search queries, for example,
http://graph.facebook.com/search?q=watermelon%20&type=post
On the other hand, while setting a non english search result, I'm also receiving only english results, but non of the results in a result in the language of the search query.
For example,
http://graph.facebook.com/search?q=ביבי&type=post
Does not return any relevant result (the search query is "ביבי" , a word in Hebrew. None of the returned results are in Hebrew).
What could I do to fix it ?
Any suggestion will be helpful.
Thanks in advance.
To receive response in a locale which is different from your computer default locale, you should specify it with the request. Right now there are 2 ways to do that:
use &locale=he_IL in the URL (list of Facebook locales), e.g.
https://graph.facebook.com/search?q=YOUR_QUERY&type=post&fields=message&locale=he_IL
use Accept-Language header with your request, e.g.
'Accept-Language': 'he_IL,he,iw;q=0.9'
Recently, the first approach had a bug (now it works well), so I would use both of them (the first one will have more priority then another).
Note: Search across the specified locale will return posts available in this locale.

REST API versioning when using Atom for resource collections

I know this is something that has been discussed over and over, and I have done extensive research to get where I am so far, but can't seem to get over the final hurdle.
I am designing a custom REST api for our application, and have decided that I would like to version using media types e.g. application/vnd.mycompany.resource.v2+xml. I realise the pro's and con's of this model and it seems to weigh up the most flexible.
Hence my GET would look as follows:
=== REQUEST ===>
GET /workspaces/123/contacts?firstName=Neil&accessID=789264&timestamp=1317611 HTTP/1.1
Accept: application/vnd.mycompany.contact-v2+xml
<== RESPONSE ===
HTTP/1.1 200 OK
Content-Type: application/vnd.mycompany.contact-v2+xml
<contact>
<name>Neil Armstrong</name>
<mobile>+61456838435</mobile>
<email>neil.armstrong#space.com</email>
</contact>
The problem is that I would like to use Atom feeds and entrys to represent my resource collections. This way I can harness the searching and pagination of Atom without this infected my resources or API structure.
If I use Atom for my requests, my request structure now looks like:
=== REQUEST ===>
GET /workspaces/123/contacts HTTP/1.1
Accept: application/atom+xml; type=feed;
<== RESPONSE ===
HTTP/1.1 200 OK
Content-Type: application/atom+xml; type=feed;
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Contacts Feed</title>
<link rel="self" href="https://api.mycompany.com/workspaces/contacts"/>
<updated>2011-11-13T18:30:02Z</updated>
...
<entry>
<title>Neil Armstrong</title>
...
<content type="application/vnd.mycompany.contact-v2+xml">
<contact>
<name>Neil Armstrong</name>
<mobile>+61456838435</mobile>
<email>neil.armstrong#space.com</email>
</contact>
</content>
</entry>
</feed>
Using Atom to represent my collections of resources, I lose the ability to version using media types. As the media type is now hidden within the content of the Atom entry.
<content type="application/vnd.mycompany.contact-v2+xml">
What is the best practice for determining the media type version of my resource, while still utilising the power of Atom for Resource collection management?
My thinking is that I could pass it through the ACCEPT header e.g.
Accept: application/atom+xml; type=feed; version=1.0
But then this is confusing as you are asking for version 1.0 of the Atom feed, not the resource itself...
Any help would be really appreciated!!
The problem is that IMHO you're misusing the media types.
Media types give you information on the STRUCTURE of the actual payload, but not the SEMANTICS of the payload. "I know this is an XHTML page, but I don't know if it's a blog post or a item on Amazon." By being an XHTML page, you know how to get the component parts out of the payload and ask interesting questions, but interpretation of the payload is not part of the media type.
Consider an example, paraphrased from an example of Roy Fielding, sending a 10,000 bit array as a GIF file that's 100x100 pixels. GIF, as "everyone knows" is used for sending pictures, but it's really simpler than that. It's a mechanism for sending structured binary that just-happen to most-of-the-time be images. So, in this case of using it to send a 10,000 bit array (perhaps represented as a gray scale image of 00 and FF), you get the benefit of a common decoder (GIF), GIFs built in compression, etc.
But, in this case, it's not a picture. You can show it as a picture, but it's a meaningless picture. The classic semantic of it being used for the picture scenario is not relevant in this case. The benefit is the ubiquity of the the format.
Another example was years ago an engineer was doing radar studies. So, he would take the 3-view drawings of aircraft you would find in books and such, and he would encode them using a tablet in to AutoCAD drawings. The DWG format was well documented, and he had code to read them. What he wanted was the coordinates and measurements from the specific aircraft.
So, in the end he had a bunch of "meaningless" AutoCAD files with nothing but a bunch of lines in it that "made no sense". But in fact they were chock full of good information for his domain. The DWG file was the media-type, but these weren't "CAD drawings". (Can you say "spontaneous reuse"?)
It's fine to version something via media-type, but that's only relevant if the media-type is in fact changing. ATOM, as you noted, isn't changing, or at least it's not changing under your control, and you may choose not to support the new version if/when it does change. But ATOM is not changing because how it represents its information, how that information is encoded, is not changing. The information may well change, in fact it changes all the time. Every ATOM feed is different with different information. MOST have similar semantics (blog feeds), but many do not (for example, perhaps your scenario).
But how you will parse and get information out of the ATOM feed will not change. And that's what the media type represents. An encoding of information, not the information itself.
So, if you want to detect versioning, then check within your payload. Inspect it. You KNOW that for V1 of your data where, for example, the invoice number is (perhaps it's at invoice/inv_no in XPATH). If the invoice is NOT there, then what do you do? You a) look some other well known place (i.e. V2), or, b) you throw an error ("Whatever this is, it's not an invoice!"). You would have to do that no matter what, because you could be getting anything, regardless of what the version says, or the media type says, or what anything else says.
You can make your payloads forward compatible to be resistant to breaking change, then version is a matter of making use of all the information you can see. If you get A and B, then while you'd like to have C and D as well, the clients can get by with the more limited information. Of if the clients see C and D, they would know to ignore A and B, as that data is deprecated. Same with the server. If something is sending A and B, it's implied to be an older processing model than if they sent along C and D.
You can version through rel names "order" vs "order_2", old clients only know to use "order", new clients know to use "order_2" and follow that link instead.
Or you simply include a version identifier in the payload, that's an easy check as well (especially since it's early in your design).
There are a lot of ways to manage the versioning, but the media type really shouldn't be the mechanism. That's why this really isn't a "problem" with ATOM. So, it's a matter of perspective.
I have another discussion about the Accept header over here: REST API having same object, but light
This (IMHO) unrelated to your versioning issue, but it's an example of extended media-types. But that's only my perception of why and how most folks want "versioning". A case could be made this case is the same thing, but most folks associate versioning with services, not simply data representations, which this other post was mostly about.
In the end, either your client and/or server are flexible enough to handle versioned data or they're not. They will (mostly, they are computers after all. Deterministic my heinie...) do what they're told. A simple rule of "ignore stuff that you don't know" can take you quite far in terms of versioning without ever changing a v1 to a v2, regardless of your encoding. Likewise "work with what you have" is a nice rule for a flexible, tolerant server. If you have problems in either case, that's what errors, logs, operators, and 24hr pagers are for, and you need those anyway.

Updating a value RESTfully with Post

I'm rather new to REST so forgive me if this is a stupid question.
So, I have a customer resource. A customer has many credits. So, I imagine a URL for getting customer credits would be
customer/21/credits
(where 21 is a customer ID)
Now, how do I add to the credits, if I don't have the full amount of credits? E.g. a customer has 10 credits and I want to add 5. As I understand, if I'm using post I would do something like:
customer/21/credits?amount=15 (is this even correct?)
However, what if I just want to add to the existing credits? That is I want to send 5 credits and say add them to whatever the customer currently has? Do I define a kind of phantom resource such as addedCredits?
customer/21/addedCredits?amount=5
then behind the scenes, I just do credits += 5?
You need to define how you're going to treat "credits" in your system; it matters whether or not you intend to define them as resources or as an attribute of your customer resource.
In the examples below, I'm going to use XML to represent the resources/entities. This may work for you, but you'll need to have some consistent way of representing your resources in requests and responses - this will help you avoid using query parameters (e.g. http://example.com?foo=bar) to define data that belongs in the request body.
A couple of ways of representing credits:
If a "credit" is an attribute of your "customer":
<customer id="21">
<balance>10</balance><!-- aka credit -->
</customer>
Then you might as well just GET the customer, update the credit/balance with your client, and then PUT the <customer> back to /customer/21.
If a "credit" is its own resource:
You can POST the following to /credit:
<credit>
<dateApplied>2009-10-15 15:00:00</dateApplied>
<customer href="/customer/21"/>
<amount>5</amount>
</credit>
Or you can POST the following to /customer/21/credits (assuming that URI is a list of all of the <credit>s applied to the customer):
<credit>
<dateApplied>2009-10-15 15:00:00</dateApplied>
<amount>5</amount>
</credit>
This would "append" a new <credit> to the existing list. And also eliminates the need to provide the <customer> in the entity, since it's already present in the URI.
I would use the same URL.
POST to customer/21/credits with a POST variable called extraCredit set to 5. POST is supposed to be used for annotation of existing resources (or creating subordinate resources). There is no reason why you should need a new URL.
If an individual credit is a resource in your system that deserves its own URL, then the response URL from POSTing to customer/21/credits should include the URL of the new credit resource e.g. customer/21/credit/12.
You could define an XML representation of credits to POST to customer/21/credits, but I would not consider it worthwhile in this simple example. REST payloads do not have to be XML.
A URL like customer/21/addedCredits?amount=5 doesn't make sense to me because it doesn't really identify a resource. If someone issues a GET to customer/21/addedCredits?amount=5 what would you return to them?
The one thing you should definitely not do is change the state of the customer resource when someone GETs a URL like customer/21/addedCredits?amount=5. Since the title of your question acknowledges that you will need to use POST your probably realise this. GET is supposed to be safe, which means that issuing a GET shouldn't change a resource's state.
Ultimately the implementation is up to you. WHile URI query parameters are generally frowned upon, it doesn't mean you can't use them. Personally I would make the post URI something like:
customer/21/credits/add/5
but nothing says you can't do something like what you have or :
customer/21/credits/add?value=5
For starters using the URI query parameters should be a "bad smell" to you. Second you need to look at defining some mime types that your clients and server can talk in so for instance with your credit example:
If I do a GET on customer/21/credits I might get a document like this:
Content-type : application/vnd.creditstore+xml
<credits>
<user>21</user>
<credits>10</credits>
Add credits to this account
</credits>
This tells a client who understands your vocab that if they want to add credits to this user they need to post something to that link. This is HATEOAS (god I hate that acronym, I probably even spelled it wrong).
Now this is all completely off the top of my head, and I probably butchered that XML example but it should get you thinking in the right direction.