diff options
Diffstat (limited to 'doc/src/guide/req.asciidoc')
-rw-r--r-- | doc/src/guide/req.asciidoc | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/doc/src/guide/req.asciidoc b/doc/src/guide/req.asciidoc new file mode 100644 index 0000000..09d442a --- /dev/null +++ b/doc/src/guide/req.asciidoc @@ -0,0 +1,247 @@ +[[req]] +== 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. + +[source,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. + +[source,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. + +[source,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. + +[source,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. + +[source,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. + +[source,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. + +[source,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. + +[source,erlang] +PathInfo = cowboy_req:path_info(Req). + +=== Query string + +The raw query string can be obtained directly. + +[source,erlang] +Qs = cowboy_req:qs(Req). + +You can parse the query string and then use standard library +functions to access individual values. + +[source,erlang] +QsVals = cowboy_req:parse_qs(Req), +{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals). + +You can match the query string into a map. + +[source,erlang] +#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req). + +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. + +[source,erlang] +QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req). + +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. + +[source,erlang] +#{lang := Lang} = cowboy_req:match_qs([{lang, [], <<"en-US">>}], Req). + +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. + +[source,erlang] +URL = cowboy_req:url(Req). + +You can also obtain only the base of the URL, excluding the +path and query string. + +[source,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. + +[source,erlang] +HeaderVal = cowboy_req:header(<<"content-type">>, Req). + +You can of course set a default in case the header is missing. + +[source,erlang] +HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>). + +And also obtain all headers. + +[source,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. + +[source,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. + +[source,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. + +[source,erlang] +MetaVal = cowboy_req:meta(websocket_version, Req). + +You can change the default value if needed. + +[source,erlang] +MetaVal = cowboy_req:meta(websocket_version, Req, 13). + +You can also define your own meta values. The name must be +an `atom()`. + +[source,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. + +[source,erlang] +{IP, Port} = cowboy_req:peer(Req). |