1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,154 @@ |
0 |
+--- |
|
1 |
+layout: post |
|
2 |
+title: "A quick look at REST" |
|
3 |
+date: 2013-10-06 14:27 |
|
4 |
+comments: true |
|
5 |
+categories: [server, shell, webdev] |
|
6 |
+cover: /images/cover/avatar.png |
|
7 |
+keywords: rest, restful, Representational State Transfer, crud, api, post, get, put, delete |
|
8 |
+description: An intro to REST |
|
9 |
+--- |
|
10 |
+ |
|
11 |
+Three months ago I've chosen a |
|
12 |
+[REST](http://en.wikipedia.org/wiki/Representational_state_transfer) |
|
13 |
+architecture for designing my new project at work. The project goal is to create |
|
14 |
+<abbr title="Application Programming Interface">API</abbr> for managing gyms, |
|
15 |
+trainings and trainees. |
|
16 |
+ |
|
17 |
+This article is just light intro to the REST world, don't expect cool tips & |
|
18 |
+tricks (maybe in next article). |
|
19 |
+ |
|
20 |
+# HTTP request methods |
|
21 |
+ |
|
22 |
+REST without using proper [HTTP methods](http://en.wikipedia.org/wiki/ |
|
23 |
+Hypertext_Transfer_Protocol#Request_methods) is a nonsense. There are about 9 |
|
24 |
+methods but we need only 4. |
|
25 |
+ |
|
26 |
+* ```POST``` -- create a new resource |
|
27 |
+* ```GET``` -- get resource data |
|
28 |
+* ```PUT``` -- update a resource |
|
29 |
+* ```DELETE``` -- delete a resource |
|
30 |
+ |
|
31 |
+There is also ```PATCH``` method which is very similar to ```PUT``` method. |
|
32 |
+In fact ```PUT``` should rewrite a whole resource and ```PATCH``` only update |
|
33 |
+some attributes of a resource. More about ```PUT``` vs ```PATCH``` |
|
34 |
+[here](https://restful-api-design.readthedocs.org/en/latest/methods.html#patch- |
|
35 |
+vs-put). |
|
36 |
+ |
|
37 |
+<!-- more --> |
|
38 |
+ |
|
39 |
+# Simple example (we always work with objects) |
|
40 |
+ |
|
41 |
+REST greatly improves a simplicity of using the API. Let's have a look at an |
|
42 |
+example how we manage trainings: |
|
43 |
+ |
|
44 |
+ http://api.example.com/training/ |
|
45 |
+ http://api.example.com/training/:training/ |
|
46 |
+ |
|
47 |
+We can access that URLs via ```GET```, ```POST```, ```PUT``` or ```DELETE``` |
|
48 |
+HTTP methods. If we want |
|
49 |
+to create a new training then we call the first URL. If we want to read |
|
50 |
+training data, or update data, or delete a training then we use the second URL |
|
51 |
+(just replace ```:training``` with some integer). Actually, REST force you take |
|
52 |
+an advantage of |
|
53 |
+[CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete). And |
|
54 |
+that's good. As you can see, to make operations with trainings we need just two |
|
55 |
+URLs (I call them *access points*). |
|
56 |
+ |
|
57 |
+The philosophy of REST is to access *objects*. In the example ```training``` |
|
58 |
+was the object. The reason is simple -- we can make CRUD operations (read, |
|
59 |
+write, update, delete) only with objects. |
|
60 |
+ |
|
61 |
+# Another example |
|
62 |
+ |
|
63 |
+Well, you can ask: "What if I need to tell a trainee X wants to join training |
|
64 |
+Y?". I solved the problem by creating another access point: |
|
65 |
+ |
|
66 |
+ http://api.example.com/training/:training/attendance/:trainee/ |
|
67 |
+ |
|
68 |
+Now we are working with ```attendance``` object. Allowed HTTP methods for this |
|
69 |
+access point are PUT and DELETE. |
|
70 |
+If a trainee with ID 541 wants to join training with ID 1050 we call |
|
71 |
+```http://api.example.com/training/1050/attendance/541/``` with ```PUT``` |
|
72 |
+method. Later the trainee changes his mind and wants to leave the training, so |
|
73 |
+we call the same URL with ```DELETE``` method. |
|
74 |
+ |
|
75 |
+# How to send data to server with cURL |
|
76 |
+ |
|
77 |
+I'll illustrate using REST API with curl utility. |
|
78 |
+ |
|
79 |
+## POST method: |
|
80 |
+ |
|
81 |
+Let's create a new training: |
|
82 |
+ |
|
83 |
+{% codeblock lang:bash %} |
|
84 |
+ curl -X POST \ |
|
85 |
+ --data-urlencode "starts_at=2013-12-12 12:00" \ |
|
86 |
+ --data-urlencode "ends_at=2013-12-12 13:00" \ |
|
87 |
+ --data-urlencode "name=New training" \ |
|
88 |
+ http://api.example.com/training/ |
|
89 |
+{% endcodeblock %} |
|
90 |
+ |
|
91 |
+A simplified server response can look like this (in JSON): |
|
92 |
+ |
|
93 |
+{% codeblock lang:json %} |
|
94 |
+{ |
|
95 |
+ "id" : 800, |
|
96 |
+ "name" : "New training", |
|
97 |
+ "starts_at" : "2013-12-12T12:00:00+0100", |
|
98 |
+ "ends_at" : "2013-12-12T13:00:00+0100", |
|
99 |
+ "created_at" : "2013-10-06T17:23:12+0200", |
|
100 |
+ "updated_at" : "2013-10-06T17:23:12+0200" |
|
101 |
+} |
|
102 |
+{% endcodeblock %} |
|
103 |
+ |
|
104 |
+## GET method: |
|
105 |
+ |
|
106 |
+Now we know training ID. Getting information about training: |
|
107 |
+ |
|
108 |
+{% codeblock lang:bash %} |
|
109 |
+ curl http://api.example.com/training/123/ |
|
110 |
+{% endcodeblock %} |
|
111 |
+ |
|
112 |
+We haven't changed training data so a server response looks exactly like in |
|
113 |
+above example. |
|
114 |
+ |
|
115 |
+## PUT method: |
|
116 |
+ |
|
117 |
+I made a mistake! The training should ends at 13:30, let's change it: |
|
118 |
+ |
|
119 |
+{% codeblock lang:bash %} |
|
120 |
+ curl -X PUT \ |
|
121 |
+ --data-urlencode "ends_at=2013-12-12 13:30" \ |
|
122 |
+ http://api.example.com/training/800/ |
|
123 |
+{% endcodeblock %} |
|
124 |
+ |
|
125 |
+A simplified server response: |
|
126 |
+ |
|
127 |
+{% codeblock lang:json %} |
|
128 |
+{ |
|
129 |
+ "id" : 800, |
|
130 |
+ "name" : "New training", |
|
131 |
+ "starts_at" : "2013-12-12T12:00:00+0100", |
|
132 |
+ "ends_at" : "2013-12-12T13:30:00+0100", |
|
133 |
+ "created_at" : "2013-10-06T17:23:12+0200", |
|
134 |
+ "updated_at" : "2013-10-06T17:32:11+0200" |
|
135 |
+} |
|
136 |
+{% endcodeblock %} |
|
137 |
+ |
|
138 |
+## DELETE method: |
|
139 |
+ |
|
140 |
+This deletes training: |
|
141 |
+ |
|
142 |
+{% codeblock lang:bash %} |
|
143 |
+ curl -X DELETE \ |
|
144 |
+ http://api.example.com/training/800/ |
|
145 |
+{% endcodeblock %} |
|
146 |
+ |
|
147 |
+An obligatory server response: |
|
148 |
+ |
|
149 |
+{% codeblock lang:json %} |
|
150 |
+{ |
|
151 |
+ "success" : true |
|
152 |
+} |
|
153 |
+{% endcodeblock %} |