I've got a lot of API endpoints to document and the payloads of the POST and PUT requests can be complicated. I am documenting them with apiblueprint. I really like the way apiblueprint allows me to document URI parameters. It looks good and lets you provide the reader with all of the information they need such as (required, String or Integer, list choices/values and provide an example).
When we look at the Request section, however I'm not seeing how to provide the same level of pristine documentation. The request sections that I've seen just provide an example request.
Say we are dealing with a simple payload that just takes an integer named id that is required. Currently my request section would look like this,
Headers
Content-Type: application/json
Body
{"id":"123"}
Is the request body supposed to be this sparse? What is the best way to convey to my users all the constraints/requirements for my REST payloads?
If I understand you correctly, you are looking for a way to documen your request paramters (headers, body, etc.)
If that's the case, then use the Schema section, and write a well documented JSON-Schema
for example you current simple request will look like this:
Request
+ Headers
Content-Type: application/json
+ Schema
{
"type":"object",
"properties":{
"id": {
"type" : "string",
"required": true
}
}
}
+ Body
{"id":"123"}
Related
I'm writing an Endpoint who will extract data. My issue is, the client request need to pass a list of (very complex) object to my enpoint, along other complexe datas.
The whole thing look to complexe to pass by parameters.
Should I still use a GET? can I do it with a requestBody? Or can I do a POST with a response body ?
My endpoint still need to respect REST
the data I need to pass:
{id :"anUuid",
comment : "some very long text sometime more than 1000 char",
dataComputedByOtherServer:[{id:"anUuid",stuff:{"a lot of other stuff"}}]
}
the response body:
{
//allong with the usual REST response http code and other error message
payload:{
moreComplexData:[{id:"anUuid",stuff:{"a lot of other stuff"}}]
}
}
There's no body payload with an HTTP GET - you'll need to use POST (or PUT) to send this as needed.
A payload within a GET request message has no defined semantics -- https://www.rfc-editor.org/rfc/rfc7231#section-4.3.1
So GET is out of bounds.
In the long term, the method want may eventually be SEARCH; see https://github.com/httpwg/http-extensions/issues/943
While POST with the header defined in #942 would help, POST is still an unsafe method that poorly reflects the safe, idempotent semantics of search-like operations. I therefore argue that a a SEARCH method is needed to have a safe, idempotent method with explicit caching support, in opposition to POST which explicitly is not cacheable.
But we aren't there as of 2019: the semantics of SEARCH are still defined by the WebDAV specification, where they don't quite mean what you want.
I have a simple question that I cannot find the answer to.
My colleague is currently making a REST Api for an application, and we have a call that simply checks some information, and returns either true or false. However, we do not know what to call this type of request, as it does not retrive any resources or insert anyhing, it simply checks some information passed into the query. As far as I can understand, a GET has to retrive a resource, which this call isn't doing
What I understand is, resource in this case is either true or false. While calling the API you will expect response either true or false on the basis of information processed by API server (status will be always 200). So a GET method is still suitable for this case.
If you are not interested in response body and you want data like response code and header details, go with HEAD.
There might be a different way to express 'checking some information', and it's important to be a bit more specific as to what that means.
So lets take an arbitrary example. You're modelling blog posts and want to know if some blog post is set to 'draft'.
The 'draft' status can be its own resource, for example:
/posts/hello-world/is-draft
Doing a GET request on the is-draft resource can yield:
{
"is-draft": true
}
So to model arbitrary things as resources, the best way to think about this is to look at the result of the operation as the 'representation' and the 'thing you want to know' as the URI.
As far as I can understand, a GET has to retrive a resource, which this call isn't doing
Technically, it is retrieving a resource; see Fielding
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource.
The resource, in this case, might not load an entity in your data model, but that's OK. Not all resources have to.
Technically, I think what you have there is a "function"; all of the information that you need to compute the result is present within the URI itself? Which would mean that, if the client knew how to do the computation (and had the compute resources available), then the client would be capable of doing the work for itself.
But there's nothing wrong with having a resource that is "the result of a function".
In some API, you'll see predicates (functions that return true/false) implemented as resources that only exist (more precisely, only have "representations") if the evaluation is true.
GET /predicate?true
204 No Content
GET /predicate?false
404 Not Found
The fact that you don't need to consider the resources "state" to compute the correct response to the query is an implementation detail hidden behind the uniform interface.
It's hard to tell by the level of details you provided your question. But if you need to check whether a resource exists or not, you can use HEAD. It's identical to GET, but it doesn't return a representation in the response payload: it returns just the status code and the response headers.
Consider the following request HEAD request:
HEAD /postal-codes/10001 HTTP/1.1
Host: example.org
Content-Type: application/json
It should return 200 for a resource that exists:
HTTP/1.1 200 OK
Content-Type: application/json
And 404 for a resource that doesn't exists:
HTTP/1.1 404 Not Found
Content-Type: application/json
Depending on your needs, you could address it with POST, which can be seen as a catch all verb.
For example, consider the following request and responses:
POST /postal-codes/validation HTTP/1.1
Host: example.org
Content-Type: application/json
{ "postal-code": "10001" }
HTTP/1.1 200 OK
Content-Type: application/json
{ "postal-code": "10001", "status": "valid" }
HTTP/1.1 200 OK
Content-Type: application/json
{ "postal-code": "10001", "status": "invalid" }
I have one question that i am finding hard to clearly identify the correct answer.
My API has one endpoint that does pagination. So, in the response i have to return to the client the total number of lines afected by the query. The count of records in practice.
I have read that, i should be passing metadata like what i want in the body, enveloping it, but i have also read that, it is not ok to afect the body with meta-data and that the future is to return only non meta-data on the body meaning that it must be on the response header.
O'reilly
If the information you are conveying through a custom HTTP header is important for the correct interpretation of the request or response, include that information in the body of the request or response or the URI used for the request. Avoid custom headers for such usages.
So, my question is, what is the correct approach to the problem? Should i pass the number of lines in response headers or put it in the message body.
Thank you very much.
For pagination, you could use an envelope in the response payload:
{
"data": [...],
"paging": {
"first": "http://api.example.com/foo?page=1&size=10",
"previous": "http://api.example.com/foo?page=2&size=10"
"next": "http://api.example.com/foo?page=4&size=10"
"last": "http://api.example.com/foo?page=5&size=10"
}
}
A similar approach is described in the RFC 5005: each page of results is a separate resource, which contains hyperlinks to the previous and next page of results
You also could use the Link header (line breaks are just for readability purposes):
Link: <http://api.example.com/foo?page=1&size=10>; rel="first",
<http://api.example.com/foo?page=2&size=10>; rel="previous",
<http://api.example.com/foo?page=4&size=10>; rel="next",
<http://api.example.com/foo?page=5&size=10>; rel="last"
Check the link relations registered in IANA.
For returning the number of records, I've seen some APIs using custom headers such as X-Total-Count, but I don't recommend such approach. Send those details in the response payload then.
I am a newbie to the apigility code-connected service & was able to create a RESTful service with fetch and fetchall class method on the mapper file.
Can someone point me a good sample for insert (POST) data via REST service ?
Thank you,
Kevin
POST is going to be used for creating a new resource typically. This means that in your request you're going to want the following headers:
Accept: application/json
Content-Type: application/json
The first tells Apigility what sort of a response it is expecting. The second says that the data you'll be providing to the API will be in json format.
Apigility uses json or json+hal by default for a return and expects json for the incoming data.
When you're creating a new resource, typically you'll be persisting it in a database and as such the id of the resource will be generated by your code or database. The rest of the resource will be provided by the caller to the API. Example:
POST /api/user
{
"username": "kevin voyce",
"firstname": "kevin",
"lastname":" "voyce"
}
If you do this, you should see a response of something like
405 - Method Not Allowed
The body of the error should indicate that the method has not been defined. The error message is coming from the create method in the resource. Inside this method, you'll see an argument called $data which at this point will consist of a PHP stdClass with fields matching the stuff you passed in via the JSON body.
This is where the fields part of configuring your API in Apigility comes in. If you set up the names of the fields and put validators on the fields, Apigility will make sure that the fields that are passed in conform to and are valid according to these validators before the call is made into your API. The same applies to not just POST, but PATCH and PUT as well. This means that within your methods you don't have to worry that the input hasn't been validated (as long as you correctly configured your validators).
Every single resource I'va come across on Internet always describes very well what you can do with the GET operation, how it works and so on, bu it never explains the POST/PUT/DELETE and particularly the format of the data you pass in the HTTP body (I'm using JSON). It always says "you can make a post request and pass the appropriate data in the body".
I am struggling with what I can do and not. For example I want to know if it is possible to update one field of one entry by just sending the updated value, and not the entire object.
Is there any document that explains clearly the possibilities and limitations?
Thanks a lot.
Easy to read documentation is here: http://www.odata.org/developers/protocols
If you want all the dirty details and a strict language you can read this document: http://msdn.microsoft.com/en-us/library/dd541188(PROT.10).aspx
You can modify a value of a single property by sending a PUT request.
For example if you send a GET to this URL:
http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name
And you request JSON (through an Accept header) the response will be:
{
"d" : {
"Name": "Bread"
}
}
The "d" wrapper is there only to avoid XSS attacks so that must not be included in the requests, but the rest stays the same, so if you then send a PUT request like this:
PUT http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name HTTP/1.1
Host: services.odata.org
Content-Type: application/json
Content-Length: 20
{
"Name": "Meat"
}
It will update the property Name to value Meat. You can also send a PUT to the value itself, in which case the URL would end with $value (denotes the raw value of the property) like this:
PUT http://services.odata.org/(S(kupqbta5wqnfz2cln1qk052x))/OData/OData.svc/Products(0)/Name/$value HTTP/1.1
Host: services.odata.org
Content-Type: text/plain
Content-Length: 4
Meat
Note that this only works on primitive properties though.
The sample service on the odata.org allows you to make modifications (guarded by the session key in the URL), so can play with it there.
Google for the HTTP 1.1 specification.