123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- ::: The Req object
- The Req object is this variable that you will use to obtain
- information about a request, read the body of the request
- and send a response.
- :: A special variable
- While we call it an "object", it is not an object in the
- OOP sense of the term. In fact it is completely opaque
- to you and the only way you can perform operations using
- it is by calling the functions from the `cowboy_req`
- module.
- Almost all the calls to the `cowboy_req` module will
- return an updated request object. Just like you would
- keep the updated `State` variable in a gen_server,
- you MUST keep the updated `Req` variable in a Cowboy
- handler. Cowboy will use this object to know whether
- a response has been sent when the handler has finished
- executing.
- The Req object allows accessing both immutable and
- mutable state. This means that calling some of the
- functions twice will not produce the same result.
- For example, when streaming the request body, the
- function will return the body by chunks, one at a
- time, until there is none left.
- :: Overview of the cowboy_req interface
- With the exception of functions manipulating the request
- body, all functions return a single value. Depending on
- the function this can be the requested value (method,
- host, path, ...), a boolean (has_body, has_resp_header...)
- a new Req object (set_resp_body, set_resp_header...), or
- simply the atom `ok` (chunk, continue, ...).
- The request body reading functions may return `{Result, Req}`
- or `{Result, Value, Req}`. The functions in this category
- are `body/{1,2}`, `body_qs/{1,2}`, `part/{1,2}`, `part_body/{1,2}`.
- This chapter covers the access functions mainly. Cookies,
- request body and response functions are covered in their
- own chapters.
- :: Request
- When a client performs a request, it first sends a few required
- values. They are sent differently depending on the protocol
- being used, but the intent is the same. They indicate to the
- server the type of action it wants to do and how to locate
- the resource to perform it on.
- The method identifies the action. Standard methods include
- GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
- are case sensitive.
- ``` erlang
- Method = cowboy_req:method(Req).
- ```
- The host, port and path parts of the URL identify the resource
- being accessed. The host and port information may not be
- available if the client uses HTTP/1.0.
- ``` erlang
- Host = cowboy_req:host(Req),
- Port = cowboy_req:port(Req),
- Path = cowboy_req:path(Req).
- ```
- The version used by the client can of course also be obtained.
- ``` erlang
- Version = cowboy_req:version(Req).
- ```
- Do note however that clients claiming to implement one version
- of the protocol does not mean they implement it fully, or even
- properly.
- :: Bindings
- After routing the request, bindings are available. Bindings
- are these parts of the host or path that you chose to extract
- when defining the routes of your application.
- You can fetch a single binding. The value will be `undefined`
- if the binding doesn't exist.
- ``` erlang
- Binding = cowboy_req:binding(my_binding, Req).
- ```
- If you need a different value when the binding doesn't exist,
- you can change the default.
- ``` erlang
- Binding = cowboy_req:binding(my_binding, Req, 42).
- ```
- You can also obtain all bindings in one call. They will be
- returned as a list of key/value tuples.
- ``` erlang
- AllBindings = cowboy_req:bindings(Req).
- ```
- If you used `...` at the beginning of the route's pattern
- for the host, you can retrieve the matched part of the host.
- The value will be `undefined` otherwise.
- ``` erlang
- HostInfo = cowboy_req:host_info(Req).
- ```
- Similarly, if you used `...` at the end of the route's
- pattern for the path, you can retrieve the matched part,
- or get `undefined` otherwise.
- ``` erlang
- PathInfo = cowboy_req:path_info(Req).
- ```
- :: Query string
- The raw query string can be obtained directly.
- ``` erlang
- Qs = cowboy_req:qs(Req).
- ```
- You can parse the query string and then use standard library
- functions to access individual values.
- ``` erlang
- QsVals = cowboy_req:parse_qs(Req),
- {_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
- ```
- You can match the query string into a map.
- ``` erlang
- #{id := ID, lang := Lang} = cowboy_req:match_qs(Req, [id, lang]).
- ```
- You can use constraints to validate the values while matching
- them. The following snippet will crash if the `id` value is
- not an integer number or if the `lang` value is empty. Additionally
- the `id` value will be converted to an integer term, saving
- you a conversion step.
- ``` erlang
- QsMap = cowboy_req:match_qs(Req, [{id, int}, {lang, nonempty}]).
- ```
- Note that in the case of duplicate query string keys, the map
- value will become a list of the different values.
- Read more about ^constraints^.
- A default value can be provided. The default will be used
- if the `lang` key is not found. It will not be used if
- the key is found but has an empty value.
- ``` erlang
- #{lang := Lang} = cowboy_req:match_qs(Req, [{lang, [], <<"en-US">>}]).
- ```
- If no default is provided and the value is missing, the
- query string is deemed invalid and the process will crash.
- :: Request URL
- You can reconstruct the full URL of the resource.
- ``` erlang
- URL = cowboy_req:url(Req).
- ```
- You can also obtain only the base of the URL, excluding the
- path and query string.
- ``` erlang
- BaseURL = cowboy_req:host_url(Req).
- ```
- :: Headers
- Cowboy allows you to obtain the header values as string,
- or parsed into a more meaningful representation.
- This will get the string value of a header.
- ``` erlang
- HeaderVal = cowboy_req:header(<<"content-type">>, Req).
- ```
- You can of course set a default in case the header is missing.
- ``` erlang
- HeaderVal
- = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
- ```
- And also obtain all headers.
- ``` erlang
- AllHeaders = cowboy_req:headers(Req).
- ```
- To parse the previous header, simply call `parse_header/{2,3}`
- where you would call `header/{2,3}` otherwise.
- ``` erlang
- ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
- ```
- Cowboy will crash if it doesn't know how to parse the given
- header, or if the value is invalid.
- You can of course define a default value. Note that the default
- value you specify here is the parsed value you'd like to get
- by default.
- ``` erlang
- ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
- {<<"text">>, <<"plain">>, []}).
- ```
- The list of known headers and default values is defined in the
- manual.
- :: Meta
- Cowboy will sometimes associate some meta information with
- the request. Built-in meta values are listed in the manual
- for their respective modules.
- This will get a meta value. The returned value will be `undefined`
- if it isn't defined.
- ``` erlang
- MetaVal = cowboy_req:meta(websocket_version, Req).
- ```
- You can change the default value if needed.
- ``` erlang
- MetaVal = cowboy_req:meta(websocket_version, Req, 13).
- ```
- You can also define your own meta values. The name must be
- an `atom()`.
- ``` erlang
- Req2 = cowboy_req:set_meta(the_answer, 42, Req).
- ```
- :: Peer
- You can obtain the peer address and port number. This is
- not necessarily the actual IP and port of the client, but
- rather the one of the machine that connected to the server.
- ``` erlang
- {IP, Port} = cowboy_req:peer(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).
- ```
- You will still be able to send a reply if needed.
|