Combo.Conn (combo v0.10.0)
View SourceFunction plugs and %Plug.Conn{} helpers in the scope of Combo.
Summary
Functions
Performs content negotiation according to the given formats.
Gets the action name as an atom, or raises if unavailable.
A plug that may convert a JSON response into a JSONP one.
Adds key-value pairs to the connection's assigns.
Clears flash.
Gets the controller module as an atom, or raises if unavailable.
Returns the current request path with its default query params.
Returns the current request path with the given query params.
Returns the current request url with its default query params.
Returns the current request URL with the given query params.
Deletes the CSRF token from the process dictionary.
Gets the endpoint module as an atom, or raises if unavailable.
Fetches the flash, and puts it into assigns.
Gets or generates a CSRF token.
Gets the request format, such as "json", "html".
Gets previous url.
Sends HTML response.
Sends JSON response.
Gets the current layout for the given format.
Merges a enumerable into the flash.
Enables CSRF protection.
Puts a message under the key into flash.
Sets the given format into the connection.
Sets the layout for rendering.
Sets the layout for rendering if one was not set yet.
Sets the view for rendering if one was not set yet.
Puts current url to the session before sending the response, and it will be available as previous url for subsequence requests.
Sets the URL string or %URI{} to be used for URL generation.
Puts headers that improve browser security.
Sets the URL string or %URI{} to be used for the URL generation of statics.
Sets the view for rendering.
Sends redirect response to the given url.
Sends redirect response to the previous location.
Render the given template or the default template specified by the current action with the given assigns.
Renders the given template and assigns based on the conn information.
Gets the router module as an atom, or raises if unavailable.
Sends the given file or binary as a download.
Generates a status message from the template name.
Sends text response.
Gets the current view for the given format.
Gets the current view for the given format, or raises if no view was found.
Returns the template name rendered in the view as a string, or nil if
no template was rendered.
Returns the template name rendered in the view as a string, or raises if no template was rendered.
Types
Layout can be:
{module, layout}, where themoduleis the layout module, and thelayoutis the function name as an atom in the layout module. For example:{DemoLayout, :app}.false, which means disabling the layout.
@type view() :: module() | false
Functions
@spec accepts(Plug.Conn.t(), [binary()]) :: Plug.Conn.t()
Performs content negotiation according to the given formats.
It receives a connection, a list of formats that the server is capable of processing, and then performs content negotiation based on the request information:
request parameter
"_format". If it is present, it is considered to be the format desired by the client.request header
"accept". Fallback to parse this header and find a matching format accordingly.
It is important to notice that browsers have historically sent bad accept headers. For this reason, this function will default to "html" format whenever:
the accepted list of arguments contains the "html" format.
the accept header specified more than one media type preceded or followed by the wildcard media type
"*/*".
When the server cannot serve a response in any of the formats expected by
the client, this function raises Combo.NotAcceptableError, which is
rendered with status 406.
Examples
accepts/2 can be invoked as a function:
iex> accepts(conn, ["html", "json"])or used as a plug:
plug :accepts, ["html", "json"]Use put_format/2
accepts/2 is useful when you may want to serve different content-types
(such as HTML and JSON) from the same routes. However, if you always have
distinct routes, you can simply hardcode the format in your route pipelines:
plug :put_format, "html"Custom media types
It is possible to add custom media types to your application.
The first step is to configure new media types in your config/config.exs:
config :mime, :types, %{
"application/vnd.api+json" => ["json-api"]
}The key is the media type, the value is a list of formats the media type can
be identified with. For example, by using "json-api", you will be able to
use templates with extension "index.json-api" or to force a particular
format in a given URL by sending "?_format=json-api".
After this change, you must recompile mime:
$ mix deps.clean mime --build
$ mix deps.get
And now you can use it in accepts too:
plug :accepts, ["html", "json-api"]
@spec action_name!(Plug.Conn.t()) :: atom()
Gets the action name as an atom, or raises if unavailable.
@spec allow_jsonp( Plug.Conn.t(), keyword() ) :: Plug.Conn.t()
A plug that may convert a JSON response into a JSONP one.
In case a JSON response is returned, it will be converted to a JSONP as
long as the callback field is present in the query string. The callback
field itself defaults to "callback", but may be configured with the
:callback option.
In case there is no callback or the response is not encoded in JSON format, it is a no-op.
Only alphanumeric characters and underscore are allowed in the callback name. Otherwise an exception is raised.
Examples
# Will convert JSON to JSONP if callback=someFunction is given
plug :allow_jsonp
# Will convert JSON to JSONP if cb=someFunction is given
plug :allow_jsonp, callback: "cb"
Adds key-value pairs to the connection's assigns.
Accepts a keyword list, a map, or a single-argument function.
When a keyword list or map is given as the second argument, it merges into
the connection's assigns. It is equivalent to calling Plug.Conn.assign/3
multiple times.
When a function is given as the second argument, it takes the current
assigns as an argument and merges its return value into the connection's
assigns.
Examples
iex> assign(conn, name: "Combo", lang: "Elixir")
iex> assign(conn, %{name: "Combo", lang: "Elixir"})
iex> assign(conn, fn %{name: name, lang: lang} ->
...> %{title: Enum.join([name, lang], " | ")}
...> end)
@spec clear_flash(Plug.Conn.t()) :: Plug.Conn.t()
Clears flash.
@spec controller_module!(Plug.Conn.t()) :: atom()
Gets the controller module as an atom, or raises if unavailable.
Returns the current request path with its default query params.
See current_path/2 to override the default query params.
The path is normalized based on the conn.script_name and conn.path_info.
For example, "/foo//bar/" will become "/foo/bar". If you want the original
path, use conn.request_path instead.
Examples
iex> current_path(conn)
"/users/123?existing=param"
Returns the current request path with the given query params.
You may also retrieve only the request path by passing an empty map of params.
The path is normalized based on the conn.script_name and conn.path_info.
For example, "/foo//bar/" will become "/foo/bar". If you want the original
path, use conn.request_path instead.
Examples
iex> current_path(conn)
"/users/123?existing=param"
iex> current_path(conn, %{new: "param"})
"/users/123?new=param"
iex> current_path(conn, %{filter: %{status: ["draft", "published"]}})
"/users/123?filter[status][]=draft&filter[status][]=published"
iex> current_path(conn, %{})
"/users/123"
Returns the current request url with its default query params.
See current_url/2 to override the default query params.
Examples
iex> current_url(conn)
"https://www.example.com/users/123?existing=param"
Returns the current request URL with the given query params.
The path will be retrieved from the currently requested path via
current_path/1. The scheme, host and others will be received from the URL
configuration in your endpoint. The reason we don't use the host and scheme
information in the request is because most applications are behind proxies
and the host and scheme may not actually reflect the host and scheme accessed
by the client. If you want to access the url precisely as requested by the
client, see Plug.Conn.request_url/1.
Examples
iex> current_url(conn)
"https://www.example.com/users/123?existing=param"
iex> current_url(conn, %{new: "param"})
"https://www.example.com/users/123?new=param"
iex> current_url(conn, %{})
"https://www.example.com/users/123"Custom URL Generation
In some cases, you'll need to generate a request's URL, but using a different scheme, different host, etc. This can be accomplished in two ways.
If you want to do so in a case-by-case basis, you can define a custom function that gets the endpoint URI configuration and changes it accordingly. For example, to get the current URL always in HTTPS format:
def current_secure_url(conn, params \\ %{}) do
current_uri = URI.new!(Combo.URLBuilder.url(conn, params))
current_secure_uri = %URI{current_uri | scheme: "https"}
URI.to_string(current_secure_uri)
endIf you want all generated URLs to always have a certain schema, host, etc,
you may use put_router_url/2.
Deletes the CSRF token from the process dictionary.
Note: The token is deleted only after a response has been sent.
@spec endpoint_module!(Plug.Conn.t()) :: atom()
Gets the endpoint module as an atom, or raises if unavailable.
@spec fetch_flash( Plug.Conn.t(), keyword() ) :: Plug.Conn.t()
Fetches the flash, and puts it into assigns.
Gets or generates a CSRF token.
If a token exists, it is returned, otherwise it is generated and stored in the process dictionary.
@spec get_format(Plug.Conn.t()) :: String.t() | nil
Gets the request format, such as "json", "html".
Gets previous url.
@spec html(Plug.Conn.t(), iodata()) :: Plug.Conn.t()
Sends HTML response.
Examples
iex> html(conn, "<html><head>...")
@spec json(Plug.Conn.t(), term()) :: Plug.Conn.t()
Sends JSON response.
Examples
iex> json(conn, %{id: 123})
@spec layout(Plug.Conn.t(), format() | nil) :: layout() | nil
Gets the current layout for the given format.
If no format is given, takes the current one from the connection.
@spec merge_flash(Plug.Conn.t(), Enum.t()) :: Plug.Conn.t()
Merges a enumerable into the flash.
Examples
iex> conn = merge_flash(conn, info: "Welcome Back!")
iex> Combo.Flash.get(conn.assigns.flash, :info)
"Welcome Back!"
Enables CSRF protection.
Currently used as a wrapper function for Plug.CSRFProtection.
Check get_csrf_token/0 and delete_csrf_token/0 for retrieving and
deleting CSRF tokens.
@spec put_flash(Plug.Conn.t(), atom() | binary(), binary()) :: Plug.Conn.t()
Puts a message under the key into flash.
key can be any atom or binary value. Combo does not enforce which keys
are stored in the flash, as long as the values are internally consistent.
In general, keys like :info and :error are good ones.
Examples
iex> conn = put_flash(conn, :info, "Welcome Back!")
iex> Combo.Flash.get(conn.assigns.flash, :info)
"Welcome Back!"
@spec put_format(Plug.Conn.t(), format()) :: Plug.Conn.t()
Sets the given format into the connection.
This format is used when rendering a template which is specifed by an atom.
For example, render(conn, :show) will render "show.<format>" where the
"<format>" is the one set here.
The default format is typically set from the negotiation done in accepts/2.
@spec put_layout(Plug.Conn.t(), layout_formats()) :: Plug.Conn.t()
Sets the layout for rendering.
Raises Plug.Conn.AlreadySentError if conn is already sent.
Examples
iex> layout(conn)
false
iex> conn = put_layout(conn, html: {Demo.Web.Layouts, :app})
iex> layout(conn)
{Demo.Web.Layouts, :app}
iex> conn = put_layout(conn, html: {Demo.Web.Layouts, :print})
iex> layout(conn)
{Demo.Web.Layouts, :print}
@spec put_new_layout(Plug.Conn.t(), layout_formats()) :: Plug.Conn.t()
Sets the layout for rendering if one was not set yet.
Raises Plug.Conn.AlreadySentError if conn is already sent.
See put_layout/2 for more information.
@spec put_new_view(Plug.Conn.t(), view_formats()) :: Plug.Conn.t()
Sets the view for rendering if one was not set yet.
Raises Plug.Conn.AlreadySentError if conn is already sent.
Puts current url to the session before sending the response, and it will be available as previous url for subsequence requests.
In general, it's added to the pipeline for browser.
Sets the URL string or %URI{} to be used for URL generation.
Examples
Imagine your application is configured to run on "example.com" but after the user signs in, you want all links to use "some_user.example.com". You can do so by setting the proper router url configuration:
def put_router_url_by_user(conn) do
# user = ...
put_router_url(conn, user.account_name <> ".example.com")
endNow when you call Routes.some_route_url(conn, ...), it will use the router
url set above. Keep in mind that, if you want to generate routes to the
current domain, it is preferred to use Routes.some_route_path helpers,
as those are always relative.
Puts headers that improve browser security.
It sets the following headers, if they are not already set:
content-security-policy- setsframe-ancestorsandbase-uritoself, restricting embedding and the use of<base>element to same origin respectively. It is equivalent to setting"base-uri 'self'; frame-ancestors 'self';".referrer-policy- only send origin on cross origin requests.x-content-type-options- sets tonosniff. This requires script and style tags to be sent with proper content type.x-permitted-cross-domain-policies- sets tononeto restrict Adobe Flash Player's access to data.
A custom headers map may also be given to be merged with defaults.
It is recommended for custom header keys to be in lowercase, to avoid sending duplicate keys or invalid responses.
Sets the URL string or %URI{} to be used for the URL generation of statics.
Using this function on a %Plug.Conn{} struct tells static_url/2 to use
the given information for URL generation instead of the %Plug.Conn{}'s
endpoint configuration (much like put_router_url/2 but for static URLs).
@spec put_view(Plug.Conn.t(), view_formats()) :: Plug.Conn.t()
Sets the view for rendering.
Raises Plug.Conn.AlreadySentError if conn is already sent.
Examples
iex> put_view(conn, html: PageHTML, json: PageJSON)
@spec redirect( Plug.Conn.t(), keyword() ) :: Plug.Conn.t()
Sends redirect response to the given url.
For security, :to only accepts paths. Use the :external option to
redirect to any URL.
The response will be sent with the status code defined within the connection
, via Plug.Conn.put_status/2. If no status code is set, a 302 response is
sent.
Examples
iex> redirect(conn, to: "/login")
iex> redirect(conn, external: "https://example.com")
Sends redirect response to the previous location.
It attempts to use path from the following sources in sequence:
- the path retrieved from "Referer" request header
- the path retrieved by
get_previous_url/1. To make it work, you need to addput_previous_url/2to the pipeline first. - the path retrieved from
:fallbackoption - the root path
Examples
iex> redirect_back(conn)
iex> redirect_back(conn, fallback: ~p"/users")
@spec render(Plug.Conn.t(), template() | assigns()) :: Plug.Conn.t()
Render the given template or the default template specified by the current action with the given assigns.
See render/3 for more information.
@spec render(Plug.Conn.t(), template(), assigns()) :: Plug.Conn.t()
Renders the given template and assigns based on the conn information.
Once the template is rendered, the template format is set as the response content type (for example, an HTML template will set "text/html" as response content type) and the data is sent to the client with default status of 200.
Arguments
conn- a%Plug.Conn{}struct.template- an atom or a string. If an atom, like:index, it will render a template with the same format as the one returned byget_format/1. For example, for an HTML request, it will render the "index.html" template. If the template is a string, it must contain the extension too, like "index.html".assigns- a keyword list or a map. It's merged intoconn.assignsand have higher precedence thanconn.assigns. The merged assigns will be used in the template.
Examples
Before rendering a template, you must configure the view modules to be used. There are multiple ways to do that:
- use
use Combo.Controller, which infers the view modules at compile-time. - use
Combo.Conn.put_view/2, which sets the view modules at runtime.
use Combo.Controller
After the viets set, you can render in two ways, either passing a string with the template name and explicit format:
defmodule Demo.Web.UserController do
use Combo.Controller, formats: [:html, :json]
def show(conn, _params) do
render(conn, "show.html", message: "Hello")
end
endThe example above renders a template "show.html" from the Demo.Web.UserHTML
and sets the response content type to "text/html".
Or, if you want the template format to be set dynamically based on the request, you can pass an atom instead:
def show(conn, _params) do
render(conn, :show, message: "Hello")
endCombo.Conn.put_view/2
If the formats are not known at compile-time, you can call put_view/2 at
runtime:
defmodule Demo.Web.UserController do
use Combo.Controller
def show(conn, _params) do
conn
|> put_view(html: Demo.Web.UserHTML)
|> render("show.html", message: "Hello")
end
end
@spec router_module!(Plug.Conn.t()) :: atom()
Gets the router module as an atom, or raises if unavailable.
Sends the given file or binary as a download.
The second argument must be {:binary, contents}, where
contents will be sent as download, or{:file, path},
where path is the filesystem location of the file to
be sent. Be careful to not interpolate the path from
external parameters, as it could allow traversal of the
filesystem.
The download is achieved by setting "content-disposition"
to attachment. The "content-type" will also be set based
on the extension of the given filename but can be customized
via the :content_type and :charset options.
Options
:filename- the filename to be presented to the user as download:content_type- the content type of the file or binary sent as download. It is automatically inferred from the filename extension:disposition- specifies disposition type (:attachmentor:inline). If:attachmentwas used, user will be prompted to save the file. If:inlinewas used, the browser will attempt to open the file. Defaults to:attachment.:charset- the charset of the file, such as "utf-8". Defaults to none:offset- the bytes to offset when reading. Defaults to0:length- the total bytes to read. Defaults to:all:encode- encodes the filename usingURI.encode/2. Defaults totrue. Whenfalse, disables encoding. If you disable encoding, you need to guarantee there are no special characters in the filename, such as quotes, newlines, etc. Otherwise you can expose your application to security attacks
Examples
To send a file that is stored inside your application priv directory:
path = Application.app_dir(:my_app, "priv/example.pdf")
send_download(conn, {:file, path})When using {:file, path}, the filename is inferred from the
given path but may also be set explicitly.
To allow the user to download contents that are in memory as a binary or string:
send_download(conn, {:binary, "world"}, filename: "hello.txt")See Plug.Conn.send_file/3 and Plug.Conn.send_resp/3 if you
would like to access the low-level functions used to send files
and responses via Plug.
Generates a status message from the template name.
Examples
iex> status_message_from_template("404.html")
"Not Found"
iex> status_message_from_template("whatever.html")
"Internal Server Error"
@spec text(Plug.Conn.t(), String.Chars.t()) :: Plug.Conn.t()
Sends text response.
Examples
iex> text(conn, "hello")
iex> text(conn, :implements_to_string)
@spec view_module(Plug.Conn.t(), format() | nil) :: view()
Gets the current view for the given format.
If no format is given, takes the current one from the connection.
@spec view_module!(Plug.Conn.t(), format() | nil) :: view()
Gets the current view for the given format, or raises if no view was found.
If no format is given, takes the current one from the connection.
@spec view_template(Plug.Conn.t()) :: String.t() | nil
Returns the template name rendered in the view as a string, or nil if
no template was rendered.
@spec view_template!(Plug.Conn.t()) :: String.t()
Returns the template name rendered in the view as a string, or raises if no template was rendered.