1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nine Nines Support: Cowboy User Guide</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Change them or set them up as you like -->
<meta name="description" content="">
<meta name="author" content="(Soft10) Pol Cámara">
<!-- Stylesheets -->
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/99s.css" rel="stylesheet">
<!-- <link href="js/google-code-prettify/prettify.css" rel="stylesheet"> -->
<link href="/css/sh99s.css" rel="stylesheet"/>
<!-- Enables html5 support on older browsers, other js is placed at the end of the page to speed up loading -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="shortcut icon" href="/img/ico/favicon.ico">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png">
<link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png">
<link rel="alternate" href="/feeds/atom.xml" type="application/atom+xml" title="Nine Nines Atom Feed">
</head>
<body class="big_text docs">
<header id="page-head">
<div id="topbar" class="container">
<div class="row">
<div class="span2">
<h1 id="logo"><a href="/" title="99s">99s</a></h1>
</div>
<div class="span10">
<!-- Top navigation and social icons-->
<div id="side-header">
<nav>
<ul>
<li><a title="Erlang training" href="/training">Training</a></li>
<li><a title="Technical publications" href="/articles">Articles</a></li>
<li><a title="Our talks" href="/talks">Talks</a></li>
<li class="active"><a title="Our services" href="/support">Pricing & Sponsoring</a></li>
<li><a title="Community support" href="http://lists.ninenines.eu">Mailing Lists</a></li>
<li><a title="Contact us" href="mailto:[email protected]">Contact</a></li>
</ul>
</nav>
<ul id="social">
<li>
<a href="https://github.com/ninenines" title="Check our Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a>
</li>
<li class="dropdown" id="twitter-links">
<a href="#twitter-links" class="dropdown-toggle" data-toggle="dropdown" title="Follow us on Twitter">
<img src="/img/ico_twitter.png" data-hover="/img/ico_twitter_alt.png" alt="Twitter">
</a>
<ul class="dropdown-menu">
<li><a title="Visit Loïc Hoguin's Twitter Account" href="http://twitter.com/lhoguin">@lhoguin</a></li>
<!-- <li class="divider"></li>
<li><a title="Visit our official Twitter account" href="#">@99s</a></li> -->
</ul>
</li>
<!-- <li>
<a href="/css/" title="Add us on Linkedin"><img src="/img/ico_linkedin.png" data-hover="img/ico_linkedin_alt.png" alt="Linkedin"></a>
</li> -->
</ul>
</div>
</div>
</div>
</div>
</header>
<div id="contents" class="two_col">
<div class="container">
<div class="row">
<div id="docs" class="span9 maincol">
<h1 class="lined-header"><span>Designing a resource handler</span></h1>
<p>This chapter aims to provide you with a list of questions you must answer in order to write a good resource handler. It is meant to be usable as a step by step guide.</p>
<h2 id="the_service">The service</h2>
<p>Can the service become unavailable, and when it does, can we detect it? For example database connectivity problems may be detected early. We may also have planned outages of all or parts of the system. Implement the <code>service_available</code> callback.</p>
<p>What HTTP methods does the service implement? Do we need more than the standard OPTIONS, HEAD, GET, PUT, POST, PATCH and DELETE? Are we not using one of those at all? Implement the <code>known_methods</code> callback.</p>
<h2 id="type_of_resource_handler">Type of resource handler</h2>
<p>Am I writing a handler for a collection of resources, or for a single resource?</p>
<p>The semantics for each of these are quite different. You should not mix collection and single resource in the same handler.</p>
<h2 id="collection_handler">Collection handler</h2>
<p>Skip this section if you are not doing a collection.</p>
<p>Is the collection hardcoded or dynamic? For example if you use the route <code>/users</code> for the collection of users then the collection is hardcoded; if you use <code>/forums/:category</code> for the collection of threads then it isn't. When the collection is hardcoded you can safely assume the resource always exists.</p>
<p>What methods should I implement?</p>
<p>OPTIONS is used to get some information about the collection. It is recommended to allow it even if you do not implement it, as Cowboy has a default implementation built-in.</p>
<p>HEAD and GET are used to retrieve the collection. If you allow GET, also allow HEAD as there's no extra work required to make it work.</p>
<p>POST is used to create a new resource inside the collection. Creating a resource by using POST on the collection is useful when resources may be created before knowing their URI, usually because parts of it are generated dynamically. A common case is some kind of auto incremented integer identifier.</p>
<p>The next methods are more rarely allowed.</p>
<p>PUT is used to create a new collection (when the collection isn't hardcoded), or replace the entire collection.</p>
<p>DELETE is used to delete the entire collection.</p>
<p>PATCH is used to modify the collection using instructions given in the request body. A PATCH operation is atomic. The PATCH operation may be used for such things as reordering; adding, modifying or deleting parts of the collection.</p>
<h2 id="single_resource_handler">Single resource handler</h2>
<p>Skip this section if you are doing a collection.</p>
<p>What methods should I implement?</p>
<p>OPTIONS is used to get some information about the resource. It is recommended to allow it even if you do not implement it, as Cowboy has a default implementation built-in.</p>
<p>HEAD and GET are used to retrieve the resource. If you allow GET, also allow HEAD as there's no extra work required to make it work.</p>
<p>POST is used to update the resource.</p>
<p>PUT is used to create a new resource (when it doesn't already exist) or replace the resource.</p>
<p>DELETE is used to delete the resource.</p>
<p>PATCH is used to modify the resource using instructions given in the request body. A PATCH operation is atomic. The PATCH operation may be used for adding, removing or modifying specific values in the resource.</p>
<h2 id="the_resource">The resource</h2>
<p>Following the above discussion, implement the <code>allowed_methods</code> callback.</p>
<p>Does the resource always exist? If it may not, implement the <code>resource_exists</code> callback.</p>
<p>Do I need to authenticate the client before they can access the resource? What authentication mechanisms should I provide? This may include form-based, token-based (in the URL or a cookie), HTTP basic, HTTP digest, SSL certificate or any other form of authentication. Implement the <code>is_authorized</code> callback.</p>
<p>Do I need fine-grained access control? How do I determine that they are authorized access? Handle that in your <code>is_authorized</code> callback.</p>
<p>Can access to a resource be forbidden regardless of access being authorized? A simple example of that is censorship of a resource. Implement the <code>forbidden</code> callback.</p>
<p>Is there any constraints on the length of the resource URI? For example the URI may be used as a key in storage and may have a limit in length. Implement <code>uri_too_long</code>.</p>
<h2 id="representations">Representations</h2>
<p>What media types do I provide? If text based, what charsets are provided? What languages do I provide?</p>
<p>Implement the mandatory <code>content_types_provided</code>. Prefix the callbacks with <code>to_</code> for clarity. For example <code>to_html</code> or <code>to_text</code>.</p>
<p>Implement the <code>languages_provided</code> or <code>charsets_provided</code> callbacks if applicable.</p>
<p>Is there any other header that may make the representation of the resource vary? Implement the <code>variances</code> callback.</p>
<p>Depending on your choices for caching content, you may want to implement one or more of the <code>generate_etag</code>, <code>last_modified</code> and <code>expires</code> callbacks.</p>
<p>Do I want the user or user agent to actively choose a representation available? Send a list of available representations in the response body and implement the <code>multiple_choices</code> callback.</p>
<h2 id="redirections">Redirections</h2>
<p>Do I need to keep track of what resources were deleted? For example you may have a mechanism where moving a resource leaves a redirect link to its new location. Implement the <code>previously_existed</code> callback.</p>
<p>Was the resource moved, and is the move temporary? If it is explicitly temporary, for example due to maintenance, implement the <code>moved_temporarily</code> callback. Otherwise, implement the <code>moved_permanently</code> callback.</p>
<h2 id="the_request">The request</h2>
<p>Do we need to perform extra checks to make sure the request is valid? Cowboy will do many checks when receiving the request already, do we need more? Note that this only applies to the request-line and headers of the request, and not the body. Implement <code>malformed_request</code>.</p>
<p>May there be a request body? Will I know its size? What's the maximum size of the request body I'm willing to accept? Implement <code>valid_entity_length</code>.</p>
<p>Finally, take a look at the sections corresponding to the methods you are implementing.</p>
<h2 id="options_method">OPTIONS method</h2>
<p>Cowboy by default will send back a list of allowed methods. Do I need to add more information to the response? Implement the <code>options</code> method.</p>
<h2 id="get_and_head_methods">GET and HEAD methods</h2>
<p>If you implement the methods GET and/or HEAD, you must implement one <code>ProvideResource</code> callback for each content-type returned by the <code>content_types_provided</code> callback.</p>
<h2 id="put,_post_and_patch_methods">PUT, POST and PATCH methods</h2>
<p>If you implement the methods PUT, POST and/or PATCH, you must implement the <code>content_types_accepted</code> callback, and one <code>AcceptResource</code> callback for each content-type it returns. Prefix the <code>AcceptResource</code> callback names with <code>from_</code> for clarity. For example <code>from_html</code> or <code>from_json</code>.</p>
<p>Do we want to allow the POST method to create individual resources directly through their URI (like PUT)? Implement the <code>allow_missing_post</code> callback. It is recommended to explicitly use PUT in these cases instead.</p>
<p>May there be conflicts when using PUT to create or replace a resource? Do we want to make sure that two updates around the same time are not cancelling one another? Implement the <code>is_conflict</code> callback.</p>
<h2 id="delete_methods">DELETE methods</h2>
<p>If you implement the method DELETE, you must implement the <code>delete_resource</code> callback.</p>
<p>When <code>delete_resource</code> returns, is the resource completely removed from the server, including from any caching service? If not, and/or if the deletion is asynchronous and we have no way of knowing it has been completed yet, implement the <code>delete_completed</code> callback.</p>
<!-- a.code -->
</div>
<div class="span3 sidecol">
<div class="input-append">
<form id="form-search" class="form-search" action="#">
<input id="input-search" type="text" placeholder="Function search" autocomplete="off" autofocus class="input-medium search-query span2">
<button type="submit" class="btn btn-success">Go</button>
</form>
</div>
<h3 id="docs-nav">Navigation</h3>
<h3>See also</h3><ul><li><a href="/docs/en/cowboy/1.0/manual/">Function Reference</a></li><li><a href="/docs/en/cowboy/1.0/index.html">README</a></li></ul>
<h3>Version select</h3>
<ul>
<li><a href="/docs/en/cowboy/1.0/guide/"><strong>1.0</strong></a></li>
<li><a href="/docs/en/cowboy/HEAD/guide/"><strong>HEAD</strong></a></li>
</ul>
</div>
</div>
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="span6">
<p id="scroll-top"><a href="#">↑ Scroll to top</a></p>
<nav>
<ul>
<li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li>
</ul>
</nav>
</div>
<div class="span6 credits">
<p><img src="/img/footer_logo.png"></p>
<p>Copyright © Nine Nines 2012-2014</p>
</div>
</div>
</div>
</footer>
<!-- Javascript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="/js/bootstrap-carousel.js"></script>
<script src="/js/bootstrap-dropdown.js"></script>
<script src="/js/custom.js"></script>
<script type="text/javascript" src="/js/shCore.js"></script>
<script type="text/javascript" src="/js/shlang/shBrushBash.js"></script>
<script type="text/javascript" src="/js/shlang/shBrushErlang.js"></script>
<script type="text/javascript" src="/js/shlang/shBrushJScript.js"></script>
<script type="text/javascript" src="/js/shlang/shBrushPlain.js"></script>
<script type="text/javascript">SyntaxHighlighter.all();</script>
<script type="text/javascript" src="/js/fuse.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var f;
$.getJSON("/docs/db.json", function(data){
f = new Fuse(data, {keys: ["n"], threshold: 0.3});
$("<ul id=\"search-results\">").insertAfter("#form-search");
});
$("#input-search").keyup(function(e){if(f){if (e.which != 13 ){
var results = f.search($(this).val());
if (results.length == 0){
$("#form-search").attr("action", "#");
}else{
$("#form-search").attr("action", results[0].l);
}
$("#search-results").empty();
for (var i = 0; i < 10 && i < results.length; i++){
$("<li><a href=\"" + results[i].l + "\">" + results[i].n + "</a></li>")
.appendTo("#search-results");
}
}}});
});
</script>
</body>
</html>
|