I am trying to use apiary.io to document a JSON-RPC based API. I can get the pages formatted, but console simply does not work.
With JSON-RPC you typically only have 1 URI, such is the case with our API. Because of this, when attempting to define the methods, the blueprint editor gives the warning
Action with method POST already defined...
I figured I could ignore this, but in the apiary console when testing it will only returns the example response for the first action defined. Does anyone have a work around for this?
From what I understand from JSON-RPC spec and examples, multiple requests and responses could work for you better than defining POST endpoints multiple times.
# My API
## JSON-RPC [/endpoint]
### Doing something [POST]
+ Request Sum of numbers (application/json-rpc)
{"method": "sum", "params": {"a":3, "b":4}, "id":0}
+ Response 200 (application/json-rpc)
{"result": 7, "error": null, "id": 0}
+ Request Posting a message (application/json-rpc)
{"method": "postMessage", "params": ["Hello all!"], "id": 99}
+ Response 200 (application/json-rpc)
{"result": 1, "error": null, "id": 99}
Cons: Your API will be squashed into one or two endpoints and individual requests won't be visible in ToC.
Pros: The request-response pairing logic in Apiary mock server will then allow you to use some strategies (also described on the page linked above) to invoke different response than just the first one. However, as these strategies work only (in the time of posting this answer) with headers or status codes and they do not inspect body of incoming request's payload, you probably still won't be able to easily distinguish between your requests in console.
Possible workaround would be to give extra headers to your requests, such as X-Request: 1, X-Request: 2, etc., so the mock server can distinguish between them and return you the right response.
You can use trick with anchor, unique fragment path in api endpoint url.
# Group Awesnome JSON-RPC API
## Entity A [/#A]
### Procedure A [POST]
### Procedure B [POST]
## Entity B [/#B]
### Procedure C [POST]
### Procedure D [POST]
Related
A lot of resources say, that GraphQL should always respond with a 200 status code, even when an error occurred:
https://www.graph.cool/docs/faq/api-eep0ugh1wa/#how-does-error-handling-work-with-graphcool
https://github.com/rmosolgo/graphql-ruby/issues/1130#issuecomment-347373937
https://blog.hasura.io/handling-graphql-hasura-errors-with-react/
Because GraphQL can return multiple responses in one response, this makes sense. When a user requests two resources in one request, and only has access to the first resource, you can send back the first resource and return a forbidden error for the second resource.
However, this is just something I figured out along the way reading docs of multiple GraphQL libraries and blog posts. I didn't find anything about HTTP status codes in the offical specs, here https://spec.graphql.org/ or here https://graphql.org/
So I still have a few questions left:
Is it ok to return a HTTP 500 status code if I have an unexpected server error?
Is it ok to return a HTTP 401 status code, if credentials are wrong?
Should I include the potential HTTP status code inside the errors key of the GraphQL response like this
{
"errors" => [{
"message" => "Graphql::Forbidden",
"locations" => [],
"extensions" => {
"error_class" => "Graphql::Forbidden", "status" => 403
}
}]
}
Should I match common errors like a wrong field name to the HTTP status code 400 Bad Request?
{
"errors" => [{
"message" => "Field 'foobar' doesn't exist on type 'UserConnection'",
"locations" => [{
"line" => 1,
"column" => 11
}],
"path" => ["query", "users", "foobar"],
"extensions" => {
"status" => 400, "code" => "undefinedField", "typeName" => "UserConnection", "fieldName" => "foobar"
}
}]
}
I'd be great if you could share your experiences / resources / best practises when handling HTTP status codes in GraphQL.
GraphQL is transport-agnostic. While GraphQL services are commonly web services that accept requests over HTTP, they can and do accept requests over other transports as well. In fact, a GraphQL service can execute queries with no network requests at all -- all it needs is a query, and, optionally, a variables object and operation name.
Because of this, the GraphQL spec isn't concerned with methods, status codes or anything else specific to HTTP (it only mentions HTTP when discussing serialization). Any practices with regard to these things are at best conventions that have either evolved over time or are simply artifacts from some of the original libraries that were written for GraphQL. As such, any kind of answer to your question is going to be mostly based on opinion.
That said, because your GraphQL service shouldn't care about how its queries are received, arguably there should be a separation between its code and whatever code is handling receiving the requests and sending back the responses (like an Express app in Node.js). In other words, we could say it's never ok for your resolver code to mutate things like the response's status code. This is the current thinking in the community and most libraries only return one of two codes -- 400 if the request itself is somehow invalid and 200 otherwise.
If your entire GraphQL endpoint is guarded by some authentication logic (say your server checks for some header value), then a GraphQL request might come back with a 401 status. But this is something we handle at the web server level, not as part of your schema. It's no different if something went terribly wrong with your web server code and it had to return a 500 status, or the nginx server sitting in front of your returned a 494 (Request header too large), etc.
Traditionally, errors encountered during execution should be thrown and that's it. GraphQL extensions can be used to provide additional context when the errors are collected and serialized -- the name of the error, the stack trace, etc. However, it makes little sense to include HTTP status codes with these errors when, again, the errors have nothing to do with HTTP. Doing so unnecessarily mixes unrelated concepts -- if you want to identify the type of error, you're better off using descriptive codes like GENERIC_SERVER, INVALID_INPUT, etc.
However, conventions around error handling are also changing. Some services want to better distinguish client errors from other execution errors. It's becoming more common to see validation errors or other errors that would be shown to the end user to be returned as part of the data instead of being treated like an execution error.
type Mutation {
login(username: String!, password: String!): LoginPayload!
}
type LoginPayload {
user: User
error: Error
}
You can see payload types like these in action with public APIs like Shopify's. A variant on this approach is to utilize unions to represent a number of possible responses.
type Mutation {
login(username: String!, password: String!): LoginPayload!
}
union LoginPayload = User | InvalidCredentialsError | ExceededLoginAttemptsError
The end result is that the client errors are strongly typed and easily distinguishable from other errors that the end user doesn't care about. There's a lot of benefits to adopting these sort of conventions, but whether they are the right fit for your server is ultimately up to you.
I use google-drive-api from this link.
But I find my response is different from the api website.
My response:
{
"kind": "drive#file",
"id": "1hs6V6eDa6CYd3gtkAeRKlrOezLYpDWTfWh5VFtchFYA",
"name": "Test001",
"mimeType": "application/vnd.google-apps.spreadsheet"
}
You can see it:
But the documented file response object is very detailed.
Why are these two response results different?
Normally by default, the server sends back the full representation of a resource after processing requests. For better performance, you can ask the server to send only the fields you really need and get a partial response instead.
Google Drive api v3 has partial response enabled for most of the methods by default. To request a partial response, use the fields request parameter to specify the fields you want returned. You can use this parameter with any request that returns response data.
Example:
returns only Kind, items.title,
&fields=kind,items(title)
or
Returns everything
&fields=*
Tip: In the try me click Show standard parameters you will be able to add fields
Like at this elastic get query I see below example where per my understanding query_string is passed under request body in GET request . Is n't it ? But I believe we can't pass request body with GET request then how come this example is true ?
GET /_search
{
"query": {
"query_string" : {
"default_field" : "content",
"query" : "this AND that OR thus"
}
}
}
In fact when I used the option COPY as CURL from the stated link I see below copied text
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"query_string" : {
"default_field" : "content",
"query" : "this AND that OR thus"
}
}
}
'
Am I missing anything here or something wrong in example? In fact I do not see the way to send the request body under Postman tool.
The fact is that you can send a GET request with a body. The current HTTP standard rfc7231 (obsoletes rfc2616 and updates rfc2817) does not strictly define what must happen to a GET request with a body. The previous versions were different in this regard. For that reason, some HTTP servers allow it, but some others don't, I'm afraid. This case is mentioned in the latest standard as follows:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
In terms of Elasticsearch, using using GET for a search request is a design decision. They feel it makes more sense semantically. Because it represents a data retrieving action better than the POST verb.
On the other hand, as mentioned above, a GET request with a body is not supported universally. That's why Postman does not allow you to do so, although Kibana > Dev Tool does it by using cURL. Therefore, the Elasticsearch search API also supports POST requests to search and retrieve information. So, when you cannot make a GET request with a body, you can obtain exactly the same result by making a POST request.
This is actually very interested question. In fact, a lot of HTTP clients aren’t supporting GET requests with body (i just recently face, that iOS client in Cocoa isn’t able to do so).
I also had a lot of discussions with my colleagues - to me after using Elasticsearch for a long time GET with a body sounds like a perfectly fine HTTP request, however some may argue, that GET shouldn’t go with body at all according to HTTP standard. However, I will leave this discussion out of this answer.
In general this leads to a situation, that if you’re using client which not supporting GET, you could either change it to POST or switch to something else - I used to use cURL all the time or Kibana Dev Tools if I needed to construct complex query on the fly
Some GCP API methods require an empty request body, others require {} in the body. I can't figure out any pattern.
Examples of methods that require an empty request body, and return an error if called with {}:
https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/getIamPolicy
https://cloud.google.com/iam/reference/rest/v1/roles/list
Examples of methods that require {} in the body, and return an error if called with an empty body:
https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/getIamPolicy
https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create
Confusingly, all four of these docs say that the request body must be empty! For the second group, I'd say that's a bug: the body must be non-empty; it must be {}.
This is pretty annoying - it feels like random difference peppered across the methods? Is there any rhyme or reason here? Couldn't the body {} methods accept an empty body?
Some ideas that don't seem to explain the difference:
Since many products use IAM, those functions could have quirky behavior. But see above - getIamPolicy is different between products.
Different product teams could decide on different local conventions. But see above - the pubsub API has calls in each camp.
The first two links that you shared are HTTP GET methods, which should not have a body, as it should only retrieve data, and all the information can be passed through the URL and some query parameters.
The other two links are HTTP PUT methods, which expect a payload to update the current content of a given entity.
You can find more explanation about how the HTTP methods are defined in the IETF RFC 2616, explaining the HTTP protocol.
Suppose an HTTP server responds to a POST with a 400 response code because the request failed validation (e.g. email address not found). If the server wishes to provide more information to the client about the nature of the error, how should this be returned? For each possible content type used in requests, should there ideally be an associated "error" content type?
For example, given the request
POST /users
Content-Type: application/x-myuser
{
"email": "foo#example.com",
"name": "Michael"
}
a response might be
400 Bad Request
Content-Type: application/x-myuser-error
{
"email": "Email address foo#example.com not found"
}
Are there any good examples of "error" content types publicly available?
I don't have any examples, but it's good to always keep these in mind:
Always include a machine-readable error, and generalize as much as possible. A JSON structure like
{"error":"Email address not found!","code":"fielderror","field":"email","reason":"notfound"} (could be simplified to {"error":"...","code":"emailnotfound"})
allows API developers to properly present the error to the user (and act on the error) while it allows you to change the messages without breaking applications. It also really helps with translation of error messages, both on your end and the external developer's end.
A different approach is to simply don't return any body, and use HTTP headers to tell the user agent what went wrong. For example, you could use X-Error and X-Error-Code to show a human readable error, and a machine readable code.
Creating too many content types might be a bad thing. I personally prefer to always use application/json and let the user agent know the status by looking at the HTTP codes: 200, 400, 403, 404, 500, etc.
Definitely don't ever start making combinations of HTTP codes and content types. You don't want your users to have to learn that application/myapp/error means there's an error, UNLESS it's 200 in which case you're in the edit screen, OR when it's 302 it's not actually an error but a redirect. This is why you should probably stick with one content type.
Bottom line: always keep it simple. Make sure that there's one field which you have to look at, not two or three, when detecting a status. Once the user agent has determined the status it could choose to look at some other fields for extra info, but only after it has determined that something went wrong. Including a separate content type probably won't help there.