Content-Language for multilingual API - localization

How should I set up my API so that it can return resources in all languages instead of just one language?
Example of response:
{
"id": 1,
"name_en-CA": "Routes",
"name_fr-CA": "Circuits",
"active": true,
"type": "A",
"effective_from": "2016-04-24T03:00:00",
"effective_from": "2016-09-04T02:59:59",
}
I know there's the Accept-Language request header, but is it appropriate to respond with all languages in the absence of an Accept-Langauge header? And would I not send the Content-Language header in this case?

In usual circumstances lack of Accept-Language is highly unlikely. However, as this seems to be REST API you may expect hand-crafted requests, so it seems your question is valid.
Personally, I wouldn't send all the possible languages responding to incorrectly formed request. Instead I would probably respond 400 Bad Request.
You may decide to respond anyway. In this case I would suggest to respond with default language (i.e. en-US).

Related

What is the media type of an OpenAPI schema?

Whenever searching for this I find resources on how to specify the media type of a resource that the schema defines, but I can't see an answer on what the actual media type of the schema itself is.
Given the way HTTP works, it makes sense to me that if I request the right content type with the Accept header, my server can respond appropriately.
Thus, if I request /products with Accept: application/json I would get products in JSON format, but if I requested openapi-whatever I would get the OpenAPI schema.
I think I can probably use either application/openapi+json or application/openapi+yaml, but I can't see anything about it in the actual specification.
I'm not sure whether or not I actually want to use the Accept header for this difference, but I certainly want to respond with the correct Content-Type header in any case.
The OpenAPI Initiative's Technical Steering Committee (TSC) approved the following media types:
application/vnd.oai.openapi (YAML variant)
application/vnd.oai.openapi+json (JSON only variant)
with an optional version parameter:
application/vnd.oai.openapi;version=2.0
However, these media types are not yet registered with IANA.
This seems to be newer (Sept. 2021):
application/openapi+yaml
application/openapi+json
https://www.ietf.org/archive/id/draft-polli-rest-api-mediatypes-00.html

Why is a rails POST/PUT format different to GET by default?

Say I have a ruby model which has a name and age attribute. A GET request for one of these objects returns something like this when using rails generate scaffold:
{
"id": 1,
"name": "foo",
"age": 21,
"parent_id": 1
}
By default a POST/PUT to this resource expects:
{
"user": {
"name": "foo",
"age": 21,
"parent_id": 1
}
}
When using nested resources configured in routes the default behaviour is to add the parent id outside of this nested hash too, e.g.: PUT /parents/1/users:
{
"parent_id": 1,
"user": {
"name": "foo",
"age": 21
}
}
I can go to the controller simply enough and alter what parameters are expected, but I'd like to know why that is the case and if I risk breaking anything if changing it.
More specifically this is a Rails API and I'd like to add swagger doc generation to the API, so having this asymmetrical request body is annoying.
So in summary my questions are:
What are the advantages of this, why is it the Rails default and what do I risk breaking by changing it?
How best to add swagger support to the API in a way which doesn't have different GET responses vs PUT/POST (which seems like bad design to me, but maybe I'm wrong)?
How best/should I make the API automatically add the parent id when making a call like POST /parents/1/users, because again the default generation doesn't support it and I'm wondering if there's a reason
What are the advantages of this?
This is perhaps an opinion-based answer, which is generally frowned upon by StackOverflow, but here's my 2 cents.
In the GET request, you are simply being returned a resource. So the attributes are all you need to know:
{
"id": 1,
"name": "foo",
"age": 21,
"parent_id": 1
}
On the other hand, for this PUT request:
{
"parent_id": 1,
"user": {
"name": "foo",
"age": 21
}
}
You can think of the parameters as being split into two "sections": The parent_id (which would normally get sent as a path param, not part of the request body!) is something to "search/filter" by, whereas the user params are the attributes of the user resource to update.
This logical separation of concerns is particularly useful in the context of web forms (which is what Rails was originally/primarily designed for), especially when dealing with complex queries or "nested" attributes.
what do I risk breaking by changing it?
Nothing really.
That format, however, was "optimised" for the context of RESTful APIs and web forms.
If you'd rather use some other format then go ahead; Rails isn't forcing you to use anything here. Just beware that a naive "better design" may come back to bite you down the line.
How best to add swagger support to the API in a way which doesn't have different GET responses vs PUT/POST (which seems like bad design to me, but maybe I'm wrong)?
You can design the API any way you like. If you want "flat parameters" everywhere, then just build the Rails application like that.
How best/should I make the API automatically add the parent id when making a call like POST /parents/1/users, because again the default generation doesn't support it and I'm wondering if there's a reason
I'm not sure what you mean by "the default generation doesn't support it". The default generation of what? The swagger docs? The rails application?
Anyway... That should be implemented as a path parameter. The swagger docs should look something like this:
/parents/{parent_id}/users:
get:
description: '.....'
parameters:
- name: parent_id
in: path
description: 'ID of the parent'
required: true
type: integer
Tom Lord’s answer and note is probably better than mine.
My guess is that this mimics the behaviour of HTTP. If you GET data, you can add parameters (?name=foo). However, if you POST data, you tend to put the payload in the body of the request. And not have any parameters in the URL.
It’s likely that Rails thinks that you’re going put that JSON object into the body of the request. Whereas the GET request it’s going to split the key/values apart and send as parameters.
The advantages of keeping it the way they are is that it’ll avoid a gotcha later. I’d argue this is always the best thing to do in programming, but also especially something like Rails. But, if you’re making an API I can see why you’d want to let people send data as parameters rather than a body that needs validating.
As for Swagger, let the user know they need to send the data as a JSON string, and then use the parameters feature as expected.
Last one is a bit tricky. I guess it’s up to the design of your API. You could pass it as part of the request. Maybe take a look through sometihng like RESTful API Design to clarify your goal.

How to dynamically discover endpoint

I want to implement openid connect in my project. Right now I am hard coding the discovery url like for google - https://accounts.google.com/.well-known/openid-configuration , same for other source and then make this call and getting the endpoints for all the respective sources.
but I want to make it full dynamic. I found something on openid.net
GET /.well-known/webfinger
?resource=acct%3Ajoe%40example.com
&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer
HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Content-Type: application/jrd+json
{
"subject": "acct:joe#example.com",
"links":
[
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://server.example.com"
}
]
}
How can I do this call. What should I placed in resouces, rel ?? I am beginner in oauth process. Could you plz help me out.
very few of the major IdPs support dynamic registration. They all seem to want you to register on a web page where you can agree to their terms of use.
mojeid.cz is one I know that does. If you find others I would like to know.
I am coding up dynamic client now. It's tough. I do plan on posting it on GitHub at some point.   ..tom
Strictly speaking Dynamic Registration is not necessarily coupled one-on-one with Discovery although typically it would be.
As the OP suggests, one can lookup the Provider's metadata through applying Webfinger Discovery as described in: http://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery
The request and response would look as already presented in the question i.e. : http://openid.net/specs/openid-connect-discovery-1_0.html#URLSyntax The RP can parse the "hreft" value from the response that would present the "issuer" value (i.e. a unique DNS bound identifier for the Provider) and then construct the well-known endpoint where the Provider's configuration metadata can be retrieved from as described here: http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
Assuming that the RP already has a client_id/client_secret established with that Provider in a previous out-of-bound step, this may avoid the RP having to store and/or cache the Provider's metadata.

Require content-type 'application/json' for appropriate requests in Rails

I have an API that handles almost exclusively application/json in Rails. A few endpoints can handle application/x-www-form-urlencoded for file-uploads.
I want to enforce the content-types: when a client adds anything other than application/json I want to send an 406 - not acccepted error back, in my ApplicationController
before_action :require_content_type_json
def require_content_type_json
return if request.content_type == Mime::JSON.to_s
head status: 406
end
However, RFC 7231 (http) states that:
A sender that generates a message containing a payload body SHOULD
generate a Content-Type header field in that message unless the
intended media type of the enclosed representation is unknown to the
sender. If a Content-Type header field is not present, the recipient
MAY either assume a media type of "application/octet-stream"
([RFC2046], Section 4.5.1) or examine the data to determine its type.
I roughtly interpret that as "when the request comes with a body, the content-type must be provided by the client, else the server should assume "application/octet-stream".
Since I cannot handle octet-stream, I want to return 406 - not accepted too, there. In other words: when there is a body, a header setting the content-type to "application/json" should be present. Always.
So, how do I detect whether a user should have sent a content-type header along? Is it enough to simply check for !request.body.empty?: body is not empty?
Or should I assume that only GET/OPTIONS/HEAD requests have no body and all others do and should require a content-type?
Does Rails have any helpers or classes in place to deal with this?

best practice for boolean REST results

I have a resource
/system/resource
And I wish to ask the system a boolean question about the resource that can't
be answered by processing on the client (i.e I can't just GET the resource
and look through the actual resource data - it requires some processing
on the backend using data not available to the client). eg
/system/resource/related/otherresourcename
I want this is either return true or false. Does anyone have any
best practice examples for this type of interaction?
Possibilities that come to my mind:
use of HTTP status code, no returned body (smells wrong)
return plain text string (True, False, 1, 0) -
Not sure what string values are appropriate to use, and furthermore
this seems to be ignoring the Accept media type and always returning
plain text
come up with a boolean object for each of my support media types
and return the appropriate type (a JSON document with a single boolean
result, an XML document with a single boolean field). However this seems unwieldy.
I don't particularly want to get into a long discussion about the true meaning of a
RESTful system etc - I have used the word REST in the title because it
best expresses the general flavour of system I am designing (even if perhaps I
am tending more towards RPC over the web rather than true REST). However, if
someone has some thoughts on how a true RESTful system avoids this problem
entirely I would be happy to hear them.
hmm, difficult to answer (your example is a bit too abstract for me).
Generally you can design such a boolean information as the resource-data or as dedicated resource. Example for the domain of orders, when you want to know whether the order is completed or not (boolean question). Beware this is simplified example (world of orders much more complex ;)
Design order state as data payload
HTTP call:
HTTP GET /orders
Would give you back 200 OK with payload (json format):
{ id : "1" , completed : "true" }
Design order state as resource
HTTP call:
HTTP GET or HEAD /orders/completed/1
Now to get your "boolean" answer you can check whether the HTTP response status was 404 or 200. 400 would tell the order is NOT completed yet, 200 would tell it is completed.
To help you more you have to be more specific, what in detail is your "boolean question"? what is the real resource and related-resource?
I would think returning text/plain would be the cleanest option. As far as the accept header is concerned, if the client really can't handle text plain, then you could revert to Json, or Xml.
Personally, I would use the strings "true" and "false". Most client languages can parse those strings to their appropriate value.

Resources