layout: post title: "A quick look at REST" date: 2013-10-06 14:27 comments: true categories: [server, shell, webdev] cover: /images/cover/avatar.png keywords: rest, restful, Representational State Transfer, crud, api, post, get, put, delete
Three months ago I've chosen a REST architecture for designing my new project at work. The project goal is to create API for managing gyms, trainings and trainees.
This article is just light intro to the REST world, don't expect cool tips & tricks (maybe in next article).
REST without using proper [HTTP methods](http://en.wikipedia.org/wiki/ HypertextTransferProtocol#Request_methods) is a nonsense. There are about 9 methods but we need only 4.
POST
-- create a new resourceGET
-- get resource dataPUT
-- update a resourceDELETE
-- delete a resourceThere is also PATCH
method which is very similar to PUT
method.
In fact PUT
should rewrite a whole resource and PATCH
only update
some attributes of a resource. More about PUT
vs PATCH
[here](https://restful-api-design.readthedocs.org/en/latest/methods.html#patch-
vs-put).
REST greatly improves a simplicity of using the API. Let's have a look at an example how we manage trainings:
http://api.example.com/training/
http://api.example.com/training/:training/
We can access that URLs via GET
, POST
, PUT
or DELETE
HTTP methods. If we want
to create a new training then we call the first URL. If we want to read
training data, or update data, or delete a training then we use the second URL
(just replace :training
with some integer). Actually, REST force you take
an advantage of
CRUD. And
that's good. As you can see, to make operations with trainings we need just two
URLs (I call them access points).
The philosophy of REST is to access objects. In the example training
was the object. The reason is simple -- we can make CRUD operations (read,
write, update, delete) only with objects.
Well, you can ask: "What if I need to tell a trainee X wants to join training Y?". I solved the problem by creating another access point:
http://api.example.com/training/:training/attendance/:trainee/
Now we are working with attendance
object. Allowed HTTP methods for this
access point are PUT and DELETE.
If a trainee with ID 541 wants to join training with ID 1050 we call
http://api.example.com/training/1050/attendance/541/
with PUT
method. Later the trainee changes his mind and wants to leave the training, so
we call the same URL with DELETE
method.
I'll illustrate using REST API with curl utility.
Let's create a new training:
{% codeblock lang:bash %} curl -X POST \ --data-urlencode "startsat=2013-12-12 12:00" \ --data-urlencode "endsat=2013-12-12 13:00" \ --data-urlencode "name=New training" \ http://api.example.com/training/ {% endcodeblock %}
A simplified server response can look like this (in JSON):
{% codeblock lang:json %} { "id" : 800, "name" : "New training", "startsat" : "2013-12-12T12:00:00+0100", "endsat" : "2013-12-12T13:00:00+0100", "createdat" : "2013-10-06T17:23:12+0200", "updatedat" : "2013-10-06T17:23:12+0200" } {% endcodeblock %}
Now we know training ID. Getting information about training:
{% codeblock lang:bash %} curl http://api.example.com/training/123/ {% endcodeblock %}
We haven't changed training data so a server response looks exactly like in above example.
I made a mistake! The training should ends at 13:30, let's change it:
{% codeblock lang:bash %} curl -X PUT \ --data-urlencode "ends_at=2013-12-12 13:30" \ http://api.example.com/training/800/ {% endcodeblock %}
A simplified server response:
{% codeblock lang:json %} { "id" : 800, "name" : "New training", "startsat" : "2013-12-12T12:00:00+0100", "endsat" : "2013-12-12T13:30:00+0100", "createdat" : "2013-10-06T17:23:12+0200", "updatedat" : "2013-10-06T17:32:11+0200" } {% endcodeblock %}
This deletes training:
{% codeblock lang:bash %} curl -X DELETE \ http://api.example.com/training/800/ {% endcodeblock %}
An obligatory server response:
{% codeblock lang:json %} { "success" : true } {% endcodeblock %}
This article was also published on my school blog.