diff options
Diffstat (limited to 'guide/req.md')
-rw-r--r-- | guide/req.md | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/guide/req.md b/guide/req.md new file mode 100644 index 0000000..e13d3a5 --- /dev/null +++ b/guide/req.md @@ -0,0 +1,205 @@ +Request object +============== + +Purpose +------- + +The request object is a special variable that can be used +to interact with a request, extracting information from it +or modifying it, and sending a response. + +It's a special variable because it contains both immutable +and mutable state. This means that some operations performed +on the request object will always return the same result, +while others will not. For example, obtaining request headers +can be repeated safely. Obtaining the request body can only +be done once, as it is read directly from the socket. + +With few exceptions, all calls to the `cowboy_req` module +will return an updated request object. You MUST use the new +request object instead of the old one for all subsequent +operations. + +Request +------- + +Cowboy allows you to retrieve a lot of information about +the request. All these calls return a `{Value, Req}` tuple, +with `Value` the requested value and `Req` the updated +request object. + +The following access functions are defined in `cowboy_req`: + + * `method/1`: the request method (`<<"GET">>`, `<<"POST">>`...) + * `version/1`: the HTTP version (`{1,0}` or `{1,1}`) + * `peer/1`: the peer address and port number + * `peer_addr/1`: the peer address guessed using the request headers + * `host/1`: the hostname requested + * `host_info/1`: the result of the `[...]` match on the host + * `port/1`: the port number used for the connection + * `path/1`: the path requested + * `path_info/1`: the result of the `[...]` match on the path + * `qs/1`: the entire query string unmodified + * `qs_val/{2,3}`: the value for the requested query string key + * `qs_vals/1`: all key/values found in the query string + * `fragment/1`: the fragment part of the URL (e.g. `#nav-links`) + * `host_url/1`: the requested URL without the path, qs and fragment + * `url/1`: the requested URL + * `binding/{2,3}`: the value for the requested binding found during routing + * `bindings/1`: all key/values found during routing + * `header/{2,3}`: the value for the requested header name + * `headers/1`: all headers name/value + * `cookie/{2,3}`: the value for the requested cookie name + * `cookies/1`: all cookies name/value + * `meta/{2,3}`: the meta information for the requested key + +All the functions above that can take two or three arguments +take an optional third argument for the default value if +none is found. Otherwise it will return `undefined`. + +In addition, Cowboy allows you to parse headers using the +`parse_header/{2,3}` function, which takes a header name +as lowercase binary, the request object, and an optional +default value. It returns `{ok, ParsedValue, Req}` if it +could be parsed, `{undefined, RawValue, Req}` if Cowboy +doesn't know this header, and `{error, badarg}` if Cowboy +encountered an error while trying to parse it. + +Finally, Cowboy allows you to set request meta information +using the `set_meta/3` function, which takes a name, a value +and the request object and returns the latter modified. + +Request body +------------ + +Cowboy will not read the request body until you ask it to. +If you don't, then Cowboy will simply discard it. It will +not take extra memory space until you start reading it. + +Cowboy has a few utility functions for dealing with the +request body. + +The function `has_body/1` will return whether the request +contains a body. Note that some clients may not send the +right headers while still sending a body, but as Cowboy has +no way of detecting it this function will return `false`. + +The function `body_length/1` retrieves the size of the +request body. If the body is compressed, the value returned +here is the compressed size. If a `Transfer-Encoding` header +was passed in the request, then Cowboy will return a size +of `undefined`, as it has no way of knowing it. + +If you know the request contains a body, and that it is +of appropriate size, then you can read it directly with +either `body/1` or `body_qs/1`. Otherwise, you will want +to stream it with `stream_body/1` and `skip_body/1`, with +the streaming process optionally initialized using `init_stream/4`. + +Multipart request body +---------------------- + +Cowboy provides facilities for dealing with multipart bodies. +They are typically used for uploading files. You can use two +functions to process these bodies, `multipart_data/1` and +`multipart_skip/1`. + +Response +-------- + +You can send a response by calling the `reply/{2,3,4}` function. +It takes the status code for the response (usually `200`), +an optional list of headers, an optional body and the request +object. + +The following snippet sends a simple response with no headers +specified but with a body. + +``` erlang +{ok, Req2} = cowboy_req:reply(200, [], "Hello world!", Req). +``` + +If this is the only line in your handler then make sure to return +the `Req2` variable to Cowboy so it can know you replied. + +If you want to send HTML you'll need to specify the `Content-Type` +header so the client can properly interpret it. + +``` erlang +{ok, Req2} = cowboy_req:reply(200, + [{<<"content-type">>, <<"text/html">>}], + "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", + Req). +``` + +You only need to make sure to follow conventions and to use a +lowercase header name. + +Chunked response +---------------- + +You can also send chunked responses using `chunked_reply/{2,3}`. +Chunked responses allow you to send the body in chunks of various +sizes. It is the recommended way of performing streaming if the +client supports it. + +You must first initiate the response by calling the aforementioned +function, then you can call `chunk/2` as many times as needed. +The following snippet sends a body in three chunks. + +``` erlang +{ok, Req2} = cowboy_req:chunked_reply(200, Req), +ok = cowboy_req:chunk("Hello...", Req2), +ok = cowboy_req:chunk("chunked...", Req2), +ok = cowboy_req:chunk("world!!", Req2). +``` + +As you can see the call to `chunk/2` does not return a modified +request object. It may return an error, however, so you should +make sure that you match the return value on `ok`. + +Response preconfiguration +------------------------- + +Cowboy allows you to set response cookies, headers or body +in advance without having to send the response at the same time. +Then, when you decide to send it, all these informations will be +built into the resulting response. + +Some of the functions available for this purpose also give you +additional functionality, like `set_resp_cookie/4` which will build +the appropriate `Set-Cookie` header, or `set_resp_body_fun/{2,3}` +which allows you to stream the response body. + +Note that any value given directly to `reply/{2,3,4}` will +override all preset values. This means for example that you +can set a default body and then override it when you decide +to send a reply. + +Closing the connection +---------------------- + +HTTP/1.1 keep-alive allows clients to send more than one request +on the same connection. This can be useful for speeding up the +loading of webpages, but is not required. You can tell Cowboy +explicitly that you want to close the connection by setting the +`Connection` header to `close`. + +``` erlang +{ok, Req2} = cowboy_req:reply(200, + [{<<"connection">>, <<"close">>}], + Req). +``` + +Reducing the memory footprint +----------------------------- + +When you are done reading information from the request object +and know you are not going to access it anymore, for example +when using long-polling or Websocket, you can use the `compact/1` +function to remove most of the data from the request object and +free memory. + +``` erlang +Req2 = cowboy_req:compact(Req). +``` |