# phoenix v1.7.17 > Peace of mind from prototype to production ## Docs ### Mix.Tasks.Phx.Gen.run/1 (function) ### Mix.Tasks.Phx.Gen.Release.otp_vsn/0 (function) ### Mix.Tasks.Phx.Routes.get_url_info/2 (function) ### Phoenix (module) This is the documentation for the Phoenix project. To get started, see our [overview guides](overview.html). ### Phoenix.json_library/0 (function) Returns the configured JSON encoding library for Phoenix. To customize the JSON library, including the following in your `config/config.exs`: config :phoenix, :json_library, AlternativeJsonLibrary ### Phoenix.plug_init_mode/0 (function) Returns the `:plug_init_mode` that controls when plugs are initialized. We recommend to set it to `:runtime` in development for compilation time improvements. It must be `:compile` in production (the default). This option is passed as the `:init_mode` to `Plug.Builder.compile/3`. ### Phoenix.Channel (behaviour) Defines a Phoenix Channel. Channels provide a means for bidirectional communication from clients that integrate with the `Phoenix.PubSub` layer for soft-realtime functionality. For a conceptual overview, see the [Channels guide](channels.html). ### Topics & Callbacks - Phoenix.Channel (behaviour) Every time you join a channel, you need to choose which particular topic you want to listen to. The topic is just an identifier, but by convention it is often made of two parts: `"topic:subtopic"`. Using the `"topic:subtopic"` approach pairs nicely with the `Phoenix.Socket.channel/3` allowing you to match on all topics starting with a given prefix by using a splat (the `*` character) as the last character in the topic pattern: channel "room:*", MyAppWeb.RoomChannel Any topic coming into the router with the `"room:"` prefix would dispatch to `MyAppWeb.RoomChannel` in the above example. Topics can also be pattern matched in your channels' `join/3` callback to pluck out the scoped pattern: # handles the special `"lobby"` subtopic def join("room:lobby", _payload, socket) do {:ok, socket} end # handles any other subtopic as the room ID, for example `"room:12"`, `"room:34"` def join("room:" <> room_id, _payload, socket) do {:ok, socket} end ### Authorization - Phoenix.Channel (behaviour) Clients must join a channel to send and receive PubSub events on that channel. Your channels must implement a `join/3` callback that authorizes the socket for the given topic. For example, you could check if the user is allowed to join that particular room. To authorize a socket in `join/3`, return `{:ok, socket}`. To refuse authorization in `join/3`, return `{:error, reply}`. ### Incoming Events - Phoenix.Channel (behaviour) After a client has successfully joined a channel, incoming events from the client are routed through the channel's `handle_in/3` callbacks. Within these callbacks, you can perform any action. Incoming callbacks must return the `socket` to maintain ephemeral state. Typically you'll either forward a message to all listeners with `broadcast!/3` or reply directly to a client event for request/response style messaging. General message payloads are received as maps: def handle_in("new_msg", %{"uid" => uid, "body" => body}, socket) do ... {:reply, :ok, socket} end Binary data payloads are passed as a `{:binary, data}` tuple: def handle_in("file_chunk", {:binary, chunk}, socket) do ... {:reply, :ok, socket} end ### Broadcasts - Phoenix.Channel (behaviour) Here's an example of receiving an incoming `"new_msg"` event from one client, and broadcasting the message to all topic subscribers for this socket. def handle_in("new_msg", %{"uid" => uid, "body" => body}, socket) do broadcast!(socket, "new_msg", %{uid: uid, body: body}) {:noreply, socket} end ### Replies - Phoenix.Channel (behaviour) Replies are useful for acknowledging a client's message or responding with the results of an operation. A reply is sent only to the client connected to the current channel process. Behind the scenes, they include the client message `ref`, which allows the client to correlate the reply it receives with the message it sent. For example, imagine creating a resource and replying with the created record: def handle_in("create:post", attrs, socket) do changeset = Post.changeset(%Post{}, attrs) if changeset.valid? do post = Repo.insert!(changeset) response = MyAppWeb.PostView.render("show.json", %{post: post}) {:reply, {:ok, response}, socket} else response = MyAppWeb.ChangesetView.render("errors.json", %{changeset: changeset}) {:reply, {:error, response}, socket} end end Or you may just want to confirm that the operation succeeded: def handle_in("create:post", attrs, socket) do changeset = Post.changeset(%Post{}, attrs) if changeset.valid? do Repo.insert!(changeset) {:reply, :ok, socket} else {:reply, :error, socket} end end Binary data is also supported with replies via a `{:binary, data}` tuple: {:reply, {:ok, {:binary, bin}}, socket} If you don't want to send a reply to the client, you can return: {:noreply, socket} One situation when you might do this is if you need to reply later; see `reply/2`. ### Pushes - Phoenix.Channel (behaviour) Calling `push/3` allows you to send a message to the client which is not a reply to a specific client message. Because it is not a reply, a pushed message does not contain a client message `ref`; there is no prior client message to relate it to. Possible use cases include notifying a client that: - You've auto-saved the user's document - The user's game is ending soon - The IoT device's settings should be updated For example, you could `push/3` a message to the client in `handle_info/3` after receiving a `PubSub` message relevant to them. alias Phoenix.Socket.Broadcast def handle_info(%Broadcast{topic: _, event: event, payload: payload}, socket) do push(socket, event, payload) {:noreply, socket} end Push data can be given in the form of a map or a tagged `{:binary, data}` tuple: # client asks for their current rank. reply contains it, and client # is also pushed a leader board and a badge image def handle_in("current_rank", _, socket) do push(socket, "leaders", %{leaders: Game.get_leaders(socket.assigns.game_id)}) push(socket, "badge", {:binary, File.read!(socket.assigns.badge_path)}) {:reply, %{val: Game.get_rank(socket.assigns[:user])}, socket} end Note that in this example, `push/3` is called from `handle_in/3`; in this way you can essentially reply N times to a single message from the client. See `reply/2` for why this may be desirable. ### Intercepting Outgoing Events - Phoenix.Channel (behaviour) When an event is broadcasted with `broadcast/3`, each channel subscriber can choose to intercept the event and have their `handle_out/3` callback triggered. This allows the event's payload to be customized on a socket by socket basis to append extra information, or conditionally filter the message from being delivered. If the event is not intercepted with `Phoenix.Channel.intercept/1`, then the message is pushed directly to the client: intercept ["new_msg", "user_joined"] # for every socket subscribing to this topic, append an `is_editable` # value for client metadata. def handle_out("new_msg", msg, socket) do push(socket, "new_msg", Map.merge(msg, %{is_editable: User.can_edit_message?(socket.assigns[:user], msg)} )) {:noreply, socket} end # do not send broadcasted `"user_joined"` events if this socket's user # is ignoring the user who joined. def handle_out("user_joined", msg, socket) do unless User.ignoring?(socket.assigns[:user], msg.user_id) do push(socket, "user_joined", msg) end {:noreply, socket} end ### Broadcasting to an external topic - Phoenix.Channel (behaviour) In some cases, you will want to broadcast messages without the context of a `socket`. This could be for broadcasting from within your channel to an external topic, or broadcasting from elsewhere in your application like a controller or another process. Such can be done via your endpoint: # within channel def handle_in("new_msg", %{"uid" => uid, "body" => body}, socket) do ... broadcast_from!(socket, "new_msg", %{uid: uid, body: body}) MyAppWeb.Endpoint.broadcast_from!(self(), "room:superadmin", "new_msg", %{uid: uid, body: body}) {:noreply, socket} end # within controller def create(conn, params) do ... MyAppWeb.Endpoint.broadcast!("room:" <> rid, "new_msg", %{uid: uid, body: body}) MyAppWeb.Endpoint.broadcast!("room:superadmin", "new_msg", %{uid: uid, body: body}) redirect(conn, to: "/") end ### Terminate - Phoenix.Channel (behaviour) On termination, the channel callback `terminate/2` will be invoked with the error reason and the socket. If we are terminating because the client left, the reason will be `{:shutdown, :left}`. Similarly, if we are terminating because the client connection was closed, the reason will be `{:shutdown, :closed}`. If any of the callbacks return a `:stop` tuple, it will also trigger terminate with the reason given in the tuple. `terminate/2`, however, won't be invoked in case of errors nor in case of exits. This is the same behaviour as you find in Elixir abstractions like `GenServer` and others. Similar to `GenServer`, it would also be possible to `:trap_exit` to guarantee that `terminate/2` is invoked. This practice is not encouraged though. Generally speaking, if you want to clean something up, it is better to monitor your channel process and do the clean up from another process. All channel callbacks, including `join/3`, are called from within the channel process. Therefore, `self()` in any of them returns the PID to be monitored. ### Exit reasons when stopping a channel - Phoenix.Channel (behaviour) When the channel callbacks return a `:stop` tuple, such as: {:stop, :shutdown, socket} {:stop, {:error, :enoent}, socket} the second argument is the exit reason, which follows the same behaviour as standard `GenServer` exits. You have three options to choose from when shutting down a channel: * `:normal` - in such cases, the exit won't be logged and linked processes do not exit * `:shutdown` or `{:shutdown, term}` - in such cases, the exit won't be logged and linked processes exit with the same reason unless they're trapping exits * any other term - in such cases, the exit will be logged and linked processes exit with the same reason unless they're trapping exits ### Subscribing to external topics - Phoenix.Channel (behaviour) Sometimes you may need to programmatically subscribe a socket to external topics in addition to the internal `socket.topic`. For example, imagine you have a bidding system where a remote client dynamically sets preferences on products they want to receive bidding notifications on. Instead of requiring a unique channel process and topic per preference, a more efficient and simple approach would be to subscribe a single channel to relevant notifications via your endpoint. For example: defmodule MyAppWeb.Endpoint.NotificationChannel do use Phoenix.Channel def join("notification:" <> user_id, %{"ids" => ids}, socket) do topics = for product_id <- ids, do: "product:#{product_id}" {:ok, socket |> assign(:topics, []) |> put_new_topics(topics)} end def handle_in("watch", %{"product_id" => id}, socket) do {:reply, :ok, put_new_topics(socket, ["product:#{id}"])} end def handle_in("unwatch", %{"product_id" => id}, socket) do {:reply, :ok, MyAppWeb.Endpoint.unsubscribe("product:#{id}")} end defp put_new_topics(socket, topics) do Enum.reduce(topics, socket, fn topic, acc -> topics = acc.assigns.topics if topic in topics do acc else :ok = MyAppWeb.Endpoint.subscribe(topic) assign(acc, :topics, [topic | topics]) end end) end end Note: the caller must be responsible for preventing duplicate subscriptions. After calling `subscribe/1` from your endpoint, the same flow applies to handling regular Elixir messages within your channel. Most often, you'll simply relay the `%Phoenix.Socket.Broadcast{}` event and payload: alias Phoenix.Socket.Broadcast def handle_info(%Broadcast{topic: _, event: event, payload: payload}, socket) do push(socket, event, payload) {:noreply, socket} end ### Hibernation - Phoenix.Channel (behaviour) From Erlang/OTP 20, channels automatically hibernate to save memory after 15_000 milliseconds of inactivity. This can be customized by passing the `:hibernate_after` option to `use Phoenix.Channel`: use Phoenix.Channel, hibernate_after: 60_000 You can also set it to `:infinity` to fully disable it. ### Shutdown - Phoenix.Channel (behaviour) You can configure the shutdown behavior of each channel used when your application is shutting down by setting the `:shutdown` value on use: use Phoenix.Channel, shutdown: 5_000 It defaults to 5_000. The supported values are described under the in the `Supervisor` module docs. ### Logging - Phoenix.Channel (behaviour) By default, channel `"join"` and `"handle_in"` events are logged, using the level `:info` and `:debug`, respectively. You can change the level used for each event, or disable logs, per event type by setting the `:log_join` and `:log_handle_in` options when using `Phoenix.Channel`. For example, the following configuration logs join events as `:info`, but disables logging for incoming events: use Phoenix.Channel, log_join: :info, log_handle_in: false Note that changing an event type's level doesn't affect what is logged, unless you set it to `false`, it affects the associated level. ### Phoenix.Channel.broadcast/3 (function) Broadcast an event to all subscribers of the socket topic. The event's message must be a serializable map or a tagged `{:binary, data}` tuple where `data` is binary data. ### Examples - Phoenix.Channel.broadcast/3 (function) iex> broadcast(socket, "new_message", %{id: 1, content: "hello"}) :ok iex> broadcast(socket, "new_message", {:binary, "hello"}) :ok ### Phoenix.Channel.broadcast!/3 (function) Same as `broadcast/3`, but raises if broadcast fails. ### Phoenix.Channel.broadcast_from/3 (function) Broadcast event from pid to all subscribers of the socket topic. The channel that owns the socket will not receive the published message. The event's message must be a serializable map or a tagged `{:binary, data}` tuple where `data` is binary data. ### Examples - Phoenix.Channel.broadcast_from/3 (function) iex> broadcast_from(socket, "new_message", %{id: 1, content: "hello"}) :ok iex> broadcast_from(socket, "new_message", {:binary, "hello"}) :ok ### Phoenix.Channel.broadcast_from!/3 (function) Same as `broadcast_from/3`, but raises if broadcast fails. ### Phoenix.Channel.code_change/3 (callback) ### Phoenix.Channel.handle_call/3 (callback) Handle regular GenServer call messages. See `c:GenServer.handle_call/3`. ### Phoenix.Channel.handle_cast/2 (callback) Handle regular GenServer cast messages. See `c:GenServer.handle_cast/2`. ### Phoenix.Channel.handle_in/3 (callback) Handle incoming `event`s. Payloads are serialized before sending with the configured serializer. ### Example - Phoenix.Channel.handle_in/3 (callback) def handle_in("ping", payload, socket) do {:reply, {:ok, payload}, socket} end ### Phoenix.Channel.handle_info/2 (callback) Handle regular Elixir process messages. See `c:GenServer.handle_info/2`. ### Phoenix.Channel.handle_out/3 (callback) Intercepts outgoing `event`s. See `intercept/1`. ### Phoenix.Channel.intercept/1 (macro) Defines which Channel events to intercept for `handle_out/3` callbacks. By default, broadcasted events are pushed directly to the client, but intercepting events gives your channel a chance to customize the event for the client to append extra information or filter the message from being delivered. *Note*: intercepting events can introduce significantly more overhead if a large number of subscribers must customize a message since the broadcast will be encoded N times instead of a single shared encoding across all subscribers. ### Examples - Phoenix.Channel.intercept/1 (macro) intercept ["new_msg"] def handle_out("new_msg", payload, socket) do push(socket, "new_msg", Map.merge(payload, is_editable: User.can_edit_message?(socket.assigns[:user], payload) )) {:noreply, socket} end `handle_out/3` callbacks must return one of: {:noreply, Socket.t} | {:noreply, Socket.t, timeout | :hibernate} | {:stop, reason :: term, Socket.t} ### Phoenix.Channel.join/3 (callback) Handle channel joins by `topic`. To authorize a socket, return `{:ok, socket}` or `{:ok, reply, socket}`. To refuse authorization, return `{:error, reason}`. Payloads are serialized before sending with the configured serializer. ### Example - Phoenix.Channel.join/3 (callback) def join("room:lobby", payload, socket) do if authorized?(payload) do {:ok, socket} else {:error, %{reason: "unauthorized"}} end end ### Phoenix.Channel.push/3 (function) Sends an event directly to the connected client without requiring a prior message from the client. The event's message must be a serializable map or a tagged `{:binary, data}` tuple where `data` is binary data. Note that unlike some in client libraries, this server-side `push/3` does not return a reference. If you need to get a reply from the client and to correlate that reply with the message you pushed, you'll need to include a unique identifier in the message, track it in the Channel's state, have the client include it in its reply, and examine the ref when the reply comes to `handle_in/3`. ### Examples - Phoenix.Channel.push/3 (function) iex> push(socket, "new_message", %{id: 1, content: "hello"}) :ok iex> push(socket, "new_message", {:binary, "hello"}) :ok ### Phoenix.Channel.reply/2 (function) Replies asynchronously to a socket push. The usual way of replying to a client's message is to return a tuple from `handle_in/3` like: {:reply, {status, payload}, socket} But sometimes you need to reply to a push asynchronously - that is, after your `handle_in/3` callback completes. For example, you might need to perform work in another process and reply when it's finished. You can do this by generating a reference to the socket with `socket_ref/1` and calling `reply/2` with that ref when you're ready to reply. *Note*: A `socket_ref` is required so the `socket` itself is not leaked outside the channel. The `socket` holds information such as assigns and transport configuration, so it's important to not copy this information outside of the channel that owns it. Technically, `reply/2` will allow you to reply multiple times to the same client message, and each reply will include the client message `ref`. But the client may expect only one reply; in that case, `push/3` would be preferable for the additional messages. Payloads are serialized before sending with the configured serializer. ### Examples - Phoenix.Channel.reply/2 (function) def handle_in("work", payload, socket) do Worker.perform(payload, socket_ref(socket)) {:noreply, socket} end def handle_info({:work_complete, result, ref}, socket) do reply(ref, {:ok, result}) {:noreply, socket} end ### Phoenix.Channel.socket_ref/1 (function) Generates a `socket_ref` for an async reply. See `reply/2` for example usage. ### Phoenix.Channel.terminate/2 (callback) Invoked when the channel process is about to exit. See `c:GenServer.terminate/2`. ### Phoenix.Channel.payload/0 (type) ### Phoenix.Channel.reply/0 (type) ### Phoenix.Channel.socket_ref/0 (type) ### Phoenix.Controller (module) Controllers are used to group common functionality in the same (pluggable) module. For example, the route: get "/users/:id", MyAppWeb.UserController, :show will invoke the `show/2` action in the `MyAppWeb.UserController`: defmodule MyAppWeb.UserController do use MyAppWeb, :controller def show(conn, %{"id" => id}) do user = Repo.get(User, id) render(conn, :show, user: user) end end An action is a regular function that receives the connection and the request parameters as arguments. The connection is a `Plug.Conn` struct, as specified by the Plug library. Then we invoke `render/3`, passing the connection, the template to render (typically named after the action), and the `user: user` as assigns. We will explore all of those concepts next. ### Connection - Phoenix.Controller (module) A controller by default provides many convenience functions for manipulating the connection, rendering templates, and more. Those functions are imported from two modules: * `Plug.Conn` - a collection of low-level functions to work with the connection * `Phoenix.Controller` - functions provided by Phoenix to support rendering, and other Phoenix specific behaviour If you want to have functions that manipulate the connection without fully implementing the controller, you can import both modules directly instead of `use Phoenix.Controller`. ### Rendering and layouts - Phoenix.Controller (module) One of the main features provided by controllers is the ability to perform content negotiation and render templates based on information sent by the client. There are two ways to render content in a controller. One option is to invoke format-specific functions, such as `html/2` and `json/2`. However, most commonly controllers invoke custom modules called views. Views are modules capable of rendering a custom format. This is done by specifying the option `:formats` when defining the controller: use Phoenix.Controller, formats: [:html, :json] Now, when invoking `render/3`, a controller named `MyAppWeb.UserController` will invoke `MyAppWeb.UserHTML` and `MyAppWeb.UserJSON` respectively when rendering each format: def show(conn, %{"id" => id}) do user = Repo.get(User, id) # Will invoke UserHTML.show(%{user: user}) for html requests # Will invoke UserJSON.show(%{user: user}) for json requests render(conn, :show, user: user) end Some formats are also handy to have layouts, which render content shared across all pages. We can also specify layouts on `use`: use Phoenix.Controller, formats: [:html, :json], layouts: [html: MyAppWeb.Layouts] You can also specify formats and layouts to render by calling `put_view/2` and `put_layout/2` directly with a connection. The line above can also be written directly in your actions as: conn |> put_view(html: MyAppWeb.UserHTML, json: MyAppWeb.UserJSON) |> put_layout(html: MyAppWeb.Layouts) ### Backwards compatibility - Phoenix.Controller (module) In previous Phoenix versions, a controller you always render `MyApp.UserView`. This behaviour can be explicitly retained by passing a suffix to the formats options: use Phoenix.Controller, formats: [html: "View", json: "View"], layouts: [html: MyAppWeb.Layouts] ### Options - Phoenix.Controller (module) When used, the controller supports the following options to customize template rendering: * `:formats` - the formats this controller will render by default. For example, specifying `formats: [:html, :json]` for a controller named `MyAppWeb.UserController` will invoke `MyAppWeb.UserHTML` and `MyAppWeb.UserJSON` when respectively rendering each format. If `:formats` is not set, the default view is set to `MyAppWeb.UserView` * `:layouts` - which layouts to render for each format, for example: `[html: DemoWeb.Layouts]` Deprecated options: * `:namespace` - sets the namespace for the layout. Use `:layouts` instead * `:put_default_views` - controls whether the default view and layout should be set or not. Set `formats: []` and `layouts: []` instead ### Plug pipeline - Phoenix.Controller (module) As with routers, controllers also have their own plug pipeline. However, different from routers, controllers have a single pipeline: defmodule MyAppWeb.UserController do use MyAppWeb, :controller plug :authenticate, usernames: ["jose", "eric", "sonny"] def show(conn, params) do # authenticated users only end defp authenticate(conn, options) do if get_session(conn, :username) in options[:usernames] do conn else conn |> redirect(to: "/") |> halt() end end end The `:authenticate` plug will be invoked before the action. If the plug calls `Plug.Conn.halt/1` (which is by default imported into controllers), it will halt the pipeline and won't invoke the action. ### Guards - Phoenix.Controller (module) `plug/2` in controllers supports guards, allowing a developer to configure a plug to only run in some particular action. plug :do_something when action in [:show, :edit] Due to operator precedence in Elixir, if the second argument is a keyword list, we need to wrap the keyword in `[...]` when using `when`: plug :authenticate, [usernames: ["jose", "eric", "sonny"]] when action in [:show, :edit] plug :authenticate, [usernames: ["admin"]] when not action in [:index] The first plug will run only when action is show or edit. The second plug will always run, except for the index action. Those guards work like regular Elixir guards and the only variables accessible in the guard are `conn`, the `action` as an atom and the `controller` as an alias. ### Controllers are plugs - Phoenix.Controller (module) Like routers, controllers are plugs, but they are wired to dispatch to a particular function which is called an action. For example, the route: get "/users/:id", UserController, :show will invoke `UserController` as a plug: UserController.call(conn, :show) which will trigger the plug pipeline and which will eventually invoke the inner action plug that dispatches to the `show/2` function in `UserController`. As controllers are plugs, they implement both [`init/1`](`c:Plug.init/1`) and [`call/2`](`c:Plug.call/2`), and it also provides a function named `action/2` which is responsible for dispatching the appropriate action after the plug stack (and is also overridable). ### Overriding `action/2` for custom arguments - Phoenix.Controller (module) Phoenix injects an `action/2` plug in your controller which calls the function matched from the router. By default, it passes the conn and params. In some cases, overriding the `action/2` plug in your controller is a useful way to inject arguments into your actions that you would otherwise need to repeatedly fetch off the connection. For example, imagine if you stored a `conn.assigns.current_user` in the connection and wanted quick access to the user for every action in your controller: def action(conn, _) do args = [conn, conn.params, conn.assigns.current_user] apply(__MODULE__, action_name(conn), args) end def index(conn, _params, user) do videos = Repo.all(user_videos(user)) # ... end def delete(conn, %{"id" => id}, user) do video = Repo.get!(user_videos(user), id) # ... end ### Phoenix.Controller.accepts/2 (function) Performs content negotiation based on the available formats. It receives a connection, a list of formats that the server is capable of rendering and then proceeds to perform content negotiation based on the request information. If the client accepts any of the given formats, the request proceeds. If the request contains a "_format" parameter, it is considered to be the format desired by the client. If no "_format" parameter is available, this function will parse the "accept" header and find a matching format accordingly. This function is useful when you may want to serve different content-types (such as JSON and HTML) from the same routes. However, if you always have distinct routes, you can also disable content negotiation and simply hardcode your format of choice in your route pipelines: plug :put_format, "html" 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 "`*/*`" This function raises `Phoenix.NotAcceptableError`, which is rendered with status 406, whenever the server cannot serve a response in any of the formats expected by the client. ### Examples - Phoenix.Controller.accepts/2 (function) `accepts/2` can be invoked as a function: iex> accepts(conn, ["html", "json"]) or used as a plug: plug :accepts, ["html", "json"] plug :accepts, ~w(html json) ### Custom media types - Phoenix.Controller.accepts/2 (function) It is possible to add custom media types to your Phoenix application. The first step is to teach Plug about those new media types in your `config/config.exs` file: 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 plug: $ mix deps.clean mime --build $ mix deps.get And now you can use it in accepts too: plug :accepts, ["html", "json-api"] ### Phoenix.Controller.action_fallback/1 (macro) Registers the plug to call as a fallback to the controller action. A fallback plug is useful to translate common domain data structures into a valid `%Plug.Conn{}` response. If the controller action fails to return a `%Plug.Conn{}`, the provided plug will be called and receive the controller's `%Plug.Conn{}` as it was before the action was invoked along with the value returned from the controller action. ### Examples - Phoenix.Controller.action_fallback/1 (macro) defmodule MyController do use Phoenix.Controller action_fallback MyFallbackController def show(conn, %{"id" => id}, current_user) do with {:ok, post} <- Blog.fetch_post(id), :ok <- Authorizer.authorize(current_user, :view, post) do render(conn, "show.json", post: post) end end end In the above example, `with` is used to match only a successful post fetch, followed by valid authorization for the current user. In the event either of those fail to match, `with` will not invoke the render block and instead return the unmatched value. In this case, imagine `Blog.fetch_post/2` returned `{:error, :not_found}` or `Authorizer.authorize/3` returned `{:error, :unauthorized}`. For cases where these data structures serve as return values across multiple boundaries in our domain, a single fallback module can be used to translate the value into a valid response. For example, you could write the following fallback controller to handle the above values: defmodule MyFallbackController do use Phoenix.Controller def call(conn, {:error, :not_found}) do conn |> put_status(:not_found) |> put_view(MyErrorView) |> render(:"404") end def call(conn, {:error, :unauthorized}) do conn |> put_status(:forbidden) |> put_view(MyErrorView) |> render(:"403") end end ### Phoenix.Controller.action_name/1 (function) Returns the action name as an atom, raises if unavailable. ### Phoenix.Controller.allow_jsonp/2 (function) 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 - Phoenix.Controller.allow_jsonp/2 (function) # 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" ### Phoenix.Controller.clear_flash/1 (function) Clears all flash messages. ### Phoenix.Controller.controller_module/1 (function) Returns the controller module as an atom, raises if unavailable. ### Phoenix.Controller.current_path/1 (function) Returns the current request path with its default query parameters: iex> current_path(conn) "/users/123?existing=param" See `current_path/2` to override the default parameters. 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. ### Phoenix.Controller.current_path/2 (function) Returns the current path with the given query parameters. You may also retrieve only the request path by passing an empty map of params. ### Examples - Phoenix.Controller.current_path/2 (function) 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" 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. ### Phoenix.Controller.current_url/1 (function) Returns the current request url with its default query parameters: iex> current_url(conn) "https://www.example.com/users/123?existing=param" See `current_url/2` to override the default parameters. ### Phoenix.Controller.current_url/2 (function) Returns the current request URL with 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 Phoenix 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 - Phoenix.Controller.current_url/2 (function) 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 - Phoenix.Controller.current_url/2 (function) 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 = MyAppWeb.Endpoint.struct_url() current_path = Phoenix.Controller.current_path(conn, params) Phoenix.VerifiedRoutes.unverified_url(%URI{current_uri | scheme: "https"}, current_path) end However, if you want all generated URLs to always have a certain schema, host, etc, you may use `put_router_url/2`. ### Phoenix.Controller.delete_csrf_token/0 (function) Deletes the CSRF token from the process dictionary. *Note*: The token is deleted only after a response has been sent. ### Phoenix.Controller.endpoint_module/1 (function) Returns the endpoint module as an atom, raises if unavailable. ### Phoenix.Controller.fetch_flash/2 (function) Fetches the flash storage. ### Phoenix.Controller.get_csrf_token/0 (function) Gets or generates a CSRF token. If a token exists, it is returned, otherwise it is generated and stored in the process dictionary. ### Phoenix.Controller.get_flash/1 (function) Returns a map of previously set flash messages or an empty map. ### Examples - Phoenix.Controller.get_flash/1 (function) iex> get_flash(conn) %{} iex> conn = put_flash(conn, :info, "Welcome Back!") iex> get_flash(conn) %{"info" => "Welcome Back!"} ### Phoenix.Controller.get_flash/2 (function) Returns a message from flash by `key` (or `nil` if no message is available for `key`). ### Examples - Phoenix.Controller.get_flash/2 (function) iex> conn = put_flash(conn, :info, "Welcome Back!") iex> get_flash(conn, :info) "Welcome Back!" ### Phoenix.Controller.get_format/1 (function) Returns the request format, such as "json", "html". This format is used when rendering a template as an atom. For example, `render(conn, :foo)` will render `"foo.FORMAT"` where the format is the one set here. The default format is typically set from the negotiation done in `accepts/2`. ### Phoenix.Controller.html/2 (function) Sends html response. ### Examples - Phoenix.Controller.html/2 (function) iex> html(conn, " ...") ### Phoenix.Controller.json/2 (function) Sends JSON response. It uses the configured `:json_library` under the `:phoenix` application for `:json` to pick up the encoder module. ### Examples - Phoenix.Controller.json/2 (function) iex> json(conn, %{id: 123}) ### Phoenix.Controller.layout/2 (function) Retrieves the current layout for the given format. If no format is given, takes the current one from the connection. ### Phoenix.Controller.layout_formats/1 (function) Retrieves current layout formats. ### Phoenix.Controller.merge_flash/2 (function) Merges a map into the flash. Returns the updated connection. ### Examples - Phoenix.Controller.merge_flash/2 (function) iex> conn = merge_flash(conn, info: "Welcome Back!") iex> Phoenix.Flash.get(conn.assigns.flash, :info) "Welcome Back!" ### Phoenix.Controller.protect_from_forgery/2 (function) Enables CSRF protection. Currently used as a wrapper function for `Plug.CSRFProtection` and mainly serves as a function plug in `YourApp.Router`. Check `get_csrf_token/0` and `delete_csrf_token/0` for retrieving and deleting CSRF tokens. ### Phoenix.Controller.put_flash/3 (function) Persists a value in flash. Returns the updated connection. ### Examples - Phoenix.Controller.put_flash/3 (function) iex> conn = put_flash(conn, :info, "Welcome Back!") iex> Phoenix.Flash.get(conn.assigns.flash, :info) "Welcome Back!" ### Phoenix.Controller.put_format/2 (function) Puts the format in the connection. This format is used when rendering a template as an atom. For example, `render(conn, :foo)` will render `"foo.FORMAT"` where the format is the one set here. The default format is typically set from the negotiation done in `accepts/2`. See `get_format/1` for retrieval. ### Phoenix.Controller.put_layout/2 (function) Stores the layout for rendering. The layout must be given as keyword list where the key is the request format the layout will be applied to (such as `:html`) and the value is one of: * `{module, layout}` with the `module` the layout is defined and the name of the `layout` as an atom * `layout` when the name of the layout. This requires a layout for the given format in the shape of `{module, layout}` to be previously given * `false` which disables the layout If `false` is given without a format, all layouts are disabled. ### Examples - Phoenix.Controller.put_layout/2 (function) iex> layout(conn) false iex> conn = put_layout(conn, html: {AppView, :application}) iex> layout(conn) {AppView, :application} iex> conn = put_layout(conn, html: :print) iex> layout(conn) {AppView, :print} Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Phoenix.Controller.put_layout_formats/2 (function) Sets which formats have a layout when rendering. ### Examples - Phoenix.Controller.put_layout_formats/2 (function) iex> layout_formats(conn) ["html"] iex> put_layout_formats(conn, ["html", "mobile"]) iex> layout_formats(conn) ["html", "mobile"] Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Phoenix.Controller.put_new_layout/2 (function) Stores the layout for rendering if one was not stored yet. See `put_layout/2` for more information. Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Phoenix.Controller.put_new_view/2 (function) Stores the view for rendering if one was not stored yet. Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Phoenix.Controller.put_root_layout/2 (function) Stores the root layout for rendering. The layout must be given as keyword list where the key is the request format the layout will be applied to (such as `:html`) and the value is one of: * `{module, layout}` with the `module` the layout is defined and the name of the `layout` as an atom * `layout` when the name of the layout. This requires a layout for the given format in the shape of `{module, layout}` to be previously given * `false` which disables the layout ### Examples - Phoenix.Controller.put_root_layout/2 (function) iex> root_layout(conn) false iex> conn = put_root_layout(conn, html: {AppView, :root}) iex> root_layout(conn) {AppView, :root} iex> conn = put_root_layout(conn, html: :bare) iex> root_layout(conn) {AppView, :bare} Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Phoenix.Controller.put_router_url/2 (function) Puts the url string or `%URI{}` to be used for route generation. This function overrides the default URL generation pulled from the `%Plug.Conn{}`'s endpoint configuration. ### Examples - Phoenix.Controller.put_router_url/2 (function) 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 put_router_url(conn, get_user_from_conn(conn).account_name <> ".example.com") end Now 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. ### Phoenix.Controller.put_secure_browser_headers/2 (function) Put headers that improve browser security. It sets the following headers: * `referrer-policy` - only send origin on cross origin requests * `x-frame-options` - set to SAMEORIGIN to avoid clickjacking through iframes unless in the same origin * `x-content-type-options` - set to nosniff. This requires script and style tags to be sent with proper content type * `x-download-options` - set to noopen to instruct the browser not to open a download directly in the browser, to avoid HTML files rendering inline and accessing the security context of the application (like critical domain cookies) * `x-permitted-cross-domain-policies` - set to none to 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 in a request. Additionally, responses with mixed-case headers served over HTTP/2 are not considered valid by common clients, resulting in dropped responses. ### Phoenix.Controller.put_static_url/2 (function) Puts the URL or `%URI{}` to be used for the static url generation. 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). ### Phoenix.Controller.put_view/2 (function) Stores the view for rendering. Raises `Plug.Conn.AlreadySentError` if `conn` is already sent. ### Examples - Phoenix.Controller.put_view/2 (function) # Use single view module iex> put_view(conn, AppView) # Use multiple view module for content negotiation iex> put_view(conn, html: AppHTML, json: AppJSON) ### Phoenix.Controller.redirect/2 (function) 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 - Phoenix.Controller.redirect/2 (function) iex> redirect(conn, to: "/login") iex> redirect(conn, external: "https://elixir-lang.org") ### Phoenix.Controller.render/2 (function) Render the given template or the default template specified by the current action with the given assigns. See `render/3` for more information. ### Phoenix.Controller.render/3 (function) 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 - Phoenix.Controller.render/3 (function) * `conn` - the `Plug.Conn` struct * `template` - which may be an atom or a string. If an atom, like `:index`, it will render a template with the same format as the one returned by `get_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.json" * `assigns` - a dictionary with the assigns to be used in the view. Those assigns are merged and have higher precedence than the connection assigns (`conn.assigns`) ### Examples - Phoenix.Controller.render/3 (function) defmodule MyAppWeb.UserController do use Phoenix.Controller def show(conn, _params) do render(conn, "show.html", message: "Hello") end end The example above renders a template "show.html" from the `MyAppWeb.UserView` and sets the response content type to "text/html". In many cases, you may want the template format to be set dynamically based on the request. To do so, you can pass the template name as an atom (without the extension): def show(conn, _params) do render(conn, :show, message: "Hello") end In order for the example above to work, we need to do content negotiation with the accepts plug before rendering. You can do so by adding the following to your pipeline (in the router): plug :accepts, ["html"] ### Views - Phoenix.Controller.render/3 (function) By default, Controllers render templates in a view with a similar name to the controller. For example, `MyAppWeb.UserController` will render templates inside the `MyAppWeb.UserView`. This information can be changed any time by using the `put_view/2` function: def show(conn, _params) do conn |> put_view(MyAppWeb.SpecialView) |> render(:show, message: "Hello") end `put_view/2` can also be used as a plug: defmodule MyAppWeb.UserController do use Phoenix.Controller plug :put_view, html: MyAppWeb.SpecialView def show(conn, _params) do render(conn, :show, message: "Hello") end end ### Layouts - Phoenix.Controller.render/3 (function) Templates are often rendered inside layouts. By default, Phoenix will render layouts for html requests. For example: defmodule MyAppWeb.UserController do use Phoenix.Controller def show(conn, _params) do render(conn, "show.html", message: "Hello") end end will render the "show.html" template inside an "app.html" template specified in `MyAppWeb.LayoutView`. `put_layout/2` can be used to change the layout, similar to how `put_view/2` can be used to change the view. ### Phoenix.Controller.root_layout/2 (function) Retrieves the current root layout for the given format. If no format is given, takes the current one from the connection. ### Phoenix.Controller.router_module/1 (function) Returns the router module as an atom, raises if unavailable. ### Phoenix.Controller.scrub_params/2 (function) Scrubs the parameters from the request. This process is two-fold: * Checks to see if the `required_key` is present * Changes empty parameters of `required_key` (recursively) to nils This function is useful for removing empty strings sent via HTML forms. If you are providing an API, there is likely no need to invoke `scrub_params/2`. If the `required_key` is not present, it will raise `Phoenix.MissingParamError`. ### Examples - Phoenix.Controller.scrub_params/2 (function) iex> scrub_params(conn, "user") ### Phoenix.Controller.send_download/3 (function) 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 - Phoenix.Controller.send_download/3 (function) * `: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 (`:attachment` or `:inline`). If `:attachment` was used, user will be prompted to save the file. If `:inline` was 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 to `0` * `:length` - the total bytes to read. Defaults to `:all` * `:encode` - encodes the filename using `URI.encode/2`. Defaults to `true`. When `false`, 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 - Phoenix.Controller.send_download/3 (function) To send a file that is stored inside your application priv directory: path = Application.app_dir(:my_app, "priv/prospectus.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. ### Phoenix.Controller.status_message_from_template/1 (function) Generates a status message from the template name. ### Examples - Phoenix.Controller.status_message_from_template/1 (function) iex> status_message_from_template("404.html") "Not Found" iex> status_message_from_template("whatever.html") "Internal Server Error" ### Phoenix.Controller.text/2 (function) Sends text response. ### Examples - Phoenix.Controller.text/2 (function) iex> text(conn, "hello") iex> text(conn, :implements_to_string) ### Phoenix.Controller.view_module/2 (function) Retrieves the current view for the given format. If no format is given, takes the current one from the connection. ### Phoenix.Controller.view_template/1 (function) Returns the template name rendered in the view as a string (or nil if no template was rendered). ### Phoenix.Controller.layout/0 (type) ### Phoenix.Controller.view/0 (type) ### Phoenix.Endpoint (behaviour) Defines a Phoenix endpoint. The endpoint is the boundary where all requests to your web application start. It is also the interface your application provides to the underlying web servers. Overall, an endpoint has three responsibilities: * to provide a wrapper for starting and stopping the endpoint as part of a supervision tree * to define an initial plug pipeline for requests to pass through * to host web specific configuration for your application ### Endpoints - Phoenix.Endpoint (behaviour) An endpoint is simply a module defined with the help of `Phoenix.Endpoint`. If you have used the `mix phx.new` generator, an endpoint was automatically generated as part of your application: defmodule YourAppWeb.Endpoint do use Phoenix.Endpoint, otp_app: :your_app # plug ... # plug ... plug YourApp.Router end Endpoints must be explicitly started as part of your application supervision tree. Endpoints are added by default to the supervision tree in generated applications. Endpoints can be added to the supervision tree as follows: children = [ YourAppWeb.Endpoint ] ### Endpoint configuration - Phoenix.Endpoint (behaviour) All endpoints are configured in your application environment. For example: config :your_app, YourAppWeb.Endpoint, secret_key_base: "kjoy3o1zeidquwy1398juxzldjlksahdk3" Endpoint configuration is split into two categories. Compile-time configuration means the configuration is read during compilation and changing it at runtime has no effect. The compile-time configuration is mostly related to error handling. Runtime configuration, instead, is accessed during or after your application is started and can be read through the `c:config/2` function: YourAppWeb.Endpoint.config(:port) YourAppWeb.Endpoint.config(:some_config, :default_value) ### Compile-time configuration - Phoenix.Endpoint (behaviour) Compile-time configuration may be set on `config/dev.exs`, `config/prod.exs` and so on, but has no effect on `config/runtime.exs`: * `:code_reloader` - when `true`, enables code reloading functionality. For the list of code reloader configuration options see `Phoenix.CodeReloader.reload/1`. Keep in mind code reloading is based on the file-system, therefore it is not possible to run two instances of the same app at the same time with code reloading in development, as they will race each other and only one will effectively recompile the files. In such cases, tweak your config files so code reloading is enabled in only one of the apps or set the MIX_BUILD environment variable to give them distinct build directories * `:debug_errors` - when `true`, uses `Plug.Debugger` functionality for debugging failures in the application. Recommended to be set to `true` only in development as it allows listing of the application source code during debugging. Defaults to `false` * `:force_ssl` - ensures no data is ever sent via HTTP, always redirecting to HTTPS. It expects a list of options which are forwarded to `Plug.SSL`. By default it sets the "strict-transport-security" header in HTTPS requests, forcing browsers to always use HTTPS. If an unsafe request (HTTP) is sent, it redirects to the HTTPS version using the `:host` specified in the `:url` configuration. To dynamically redirect to the `host` of the current request, set `:host` in the `:force_ssl` configuration to `nil` ### Runtime configuration - Phoenix.Endpoint (behaviour) The configuration below may be set on `config/dev.exs`, `config/prod.exs` and so on, as well as on `config/runtime.exs`. Typically, if you need to configure them with system environment variables, you set them in `config/runtime.exs`. These options may also be set when starting the endpoint in your supervision tree, such as `{MyApp.Endpoint, options}`. * `:adapter` - which webserver adapter to use for serving web requests. See the "Adapter configuration" section below * `:cache_static_manifest` - a path to a json manifest file that contains static files and their digested version. This is typically set to "priv/static/cache_manifest.json" which is the file automatically generated by `mix phx.digest`. It can be either: a string containing a file system path or a tuple containing the application name and the path within that application. * `:cache_static_manifest_latest` - a map of the static files pointing to their digest version. This is automatically loaded from `cache_static_manifest` on boot. However, if you have your own static handling mechanism, you may want to set this value explicitly. This is used by projects such as `LiveView` to detect if the client is running on the latest version of all assets. * `:cache_manifest_skip_vsn` - when true, skips the appended query string "?vsn=d" when generating paths to static assets. This query string is used by `Plug.Static` to set long expiry dates, therefore, you should set this option to true only if you are not using `Plug.Static` to serve assets, for example, if you are using a CDN. If you are setting this option, you should also consider passing `--no-vsn` to `mix phx.digest`. Defaults to `false`. * `:check_origin` - configure the default `:check_origin` setting for transports. See `socket/3` for options. Defaults to `true`. * `:secret_key_base` - a secret key used as a base to generate secrets for encrypting and signing data. For example, cookies and tokens are signed by default, but they may also be encrypted if desired. Defaults to `nil` as it must be set per application * `:server` - when `true`, starts the web server when the endpoint supervision tree starts. Defaults to `false`. The `mix phx.server` task automatically sets this to `true` * `:url` - configuration for generating URLs throughout the app. Accepts the `:host`, `:scheme`, `:path` and `:port` options. All keys except `:path` can be changed at runtime. Defaults to: [host: "localhost", path: "/"] The `:port` option requires either an integer or string. The `:host` option requires a string. The `:scheme` option accepts `"http"` and `"https"` values. Default value is inferred from top level `:http` or `:https` option. It is useful when hosting Phoenix behind a load balancer or reverse proxy and terminating SSL there. The `:path` option can be used to override root path. Useful when hosting Phoenix behind a reverse proxy with URL rewrite rules * `:static_url` - configuration for generating URLs for static files. It will fallback to `url` if no option is provided. Accepts the same options as `url` * `:watchers` - a set of watchers to run alongside your server. It expects a list of tuples containing the executable and its arguments. Watchers are guaranteed to run in the application directory, but only when the server is enabled (unless `:force_watchers` configuration is set to `true`). For example, the watcher below will run the "watch" mode of the webpack build tool when the server starts. You can configure it to whatever build tool or command you want: [ node: [ "node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch", "--watch-options-stdin" ] ] The `:cd` and `:env` options can be given at the end of the list to customize the watcher: [node: [..., cd: "assets", env: [{"TAILWIND_MODE", "watch"}]]] A watcher can also be a module-function-args tuple that will be invoked accordingly: [another: {Mod, :fun, [arg1, arg2]}] * `:force_watchers` - when `true`, forces your watchers to start even when the `:server` option is set to `false`. * `:live_reload` - configuration for the live reload option. Configuration requires a `:patterns` option which should be a list of file patterns to watch. When these files change, it will trigger a reload. live_reload: [ url: "ws://localhost:4000", patterns: [ ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", ~r"lib/app_web/(live|views)/.*(ex)$", ~r"lib/app_web/templates/.*(eex)$" ] ] * `:pubsub_server` - the name of the pubsub server to use in channels and via the Endpoint broadcast functions. The PubSub server is typically started in your supervision tree. * `:render_errors` - responsible for rendering templates whenever there is a failure in the application. For example, if the application crashes with a 500 error during a HTML request, `render("500.html", assigns)` will be called in the view given to `:render_errors`. A `:formats` list can be provided to specify a module per format to handle error rendering. Example: [formats: [html: MyApp.ErrorHTML], layout: false, log: :debug] * `:log_access_url` - log the access url once the server boots Note that you can also store your own configurations in the Phoenix.Endpoint. For example, [Phoenix LiveView](https://hexdocs.pm/phoenix_live_view) expects its own configuration under the `:live_view` key. In such cases, you should consult the documentation of the respective projects. ### Adapter configuration - Phoenix.Endpoint (behaviour) Phoenix allows you to choose which webserver adapter to use. Newly generated applications created via the `phx.new` Mix task use the [`Bandit`](https://github.com/mtrudel/bandit) webserver via the `Bandit.PhoenixAdapter` adapter. If not otherwise specified via the `adapter` option Phoenix will fall back to the `Phoenix.Endpoint.Cowboy2Adapter` for backwards compatibility with applications generated prior to Phoenix 1.7.8. Both adapters can be configured in a similar manner using the following two top-level options: * `:http` - the configuration for the HTTP server. It accepts all options as defined by either [`Bandit`](https://hexdocs.pm/bandit/Bandit.html#t:options/0) or [`Plug.Cowboy`](https://hexdocs.pm/plug_cowboy/) depending on your choice of adapter. Defaults to `false` * `:https` - the configuration for the HTTPS server. It accepts all options as defined by either [`Bandit`](https://hexdocs.pm/bandit/Bandit.html#t:options/0) or [`Plug.Cowboy`](https://hexdocs.pm/plug_cowboy/) depending on your choice of adapter. Defaults to `false` In addition, the connection draining can be configured for the Cowboy webserver via the following top-level option (this is not required for Bandit as it has connection draining built-in): * `:drainer` - a drainer process waits for any on-going request to finish during application shutdown. It accepts the `:shutdown` and `:check_interval` options as defined by `Plug.Cowboy.Drainer`. Note the draining does not terminate any existing connection, it simply waits for them to finish. Socket connections run their own drainer before this one is invoked. That's because sockets are stateful and can be gracefully notified, which allows us to stagger them over a longer period of time. See the documentation for `socket/3` for more information ### Endpoint API - Phoenix.Endpoint (behaviour) In the previous section, we have used the `c:config/2` function that is automatically generated in your endpoint. Here's a list of all the functions that are automatically defined in your endpoint: * for handling paths and URLs: `c:struct_url/0`, `c:url/0`, `c:path/1`, `c:static_url/0`,`c:static_path/1`, and `c:static_integrity/1` * for gathering runtime information about the address and port the endpoint is running on: `c:server_info/1` * for broadcasting to channels: `c:broadcast/3`, `c:broadcast!/3`, `c:broadcast_from/4`, `c:broadcast_from!/4`, `c:local_broadcast/3`, and `c:local_broadcast_from/4` * for configuration: `c:start_link/1`, `c:config/2`, and `c:config_change/2` * as required by the `Plug` behaviour: `c:Plug.init/1` and `c:Plug.call/2` ### Phoenix.Endpoint.broadcast/3 (callback) Broadcasts a `msg` as `event` in the given `topic` to all nodes. ### Phoenix.Endpoint.broadcast!/3 (callback) Broadcasts a `msg` as `event` in the given `topic` to all nodes. Raises in case of failures. ### Phoenix.Endpoint.broadcast_from/4 (callback) Broadcasts a `msg` from the given `from` as `event` in the given `topic` to all nodes. ### Phoenix.Endpoint.broadcast_from!/4 (callback) Broadcasts a `msg` from the given `from` as `event` in the given `topic` to all nodes. Raises in case of failures. ### Phoenix.Endpoint.config/2 (callback) Access the endpoint configuration given by key. ### Phoenix.Endpoint.config_change/2 (callback) Reload the endpoint configuration on application upgrades. ### Phoenix.Endpoint.host/0 (callback) Returns the host from the :url configuration. ### Phoenix.Endpoint.local_broadcast/3 (callback) Broadcasts a `msg` as `event` in the given `topic` within the current node. ### Phoenix.Endpoint.local_broadcast_from/4 (callback) Broadcasts a `msg` from the given `from` as `event` in the given `topic` within the current node. ### Phoenix.Endpoint.path/1 (callback) Generates the path information when routing to this endpoint. ### Phoenix.Endpoint.script_name/0 (callback) Returns the script name from the :url configuration. ### Phoenix.Endpoint.server?/2 (function) Checks if Endpoint's web server has been configured to start. * `otp_app` - The OTP app running the endpoint, for example `:my_app` * `endpoint` - The endpoint module, for example `MyAppWeb.Endpoint` ### Examples - Phoenix.Endpoint.server?/2 (function) iex> Phoenix.Endpoint.server?(:my_app, MyAppWeb.Endpoint) true ### Phoenix.Endpoint.server_info/1 (callback) Returns the address and port that the server is running on ### Phoenix.Endpoint.socket/3 (macro) Defines a websocket/longpoll mount-point for a `socket`. It expects a `path`, a `socket` module, and a set of options. The socket module is typically defined with `Phoenix.Socket`. Both websocket and longpolling connections are supported out of the box. ### Options - Phoenix.Endpoint.socket/3 (macro) * `:websocket` - controls the websocket configuration. Defaults to `true`. May be false or a keyword list of options. See ["Common configuration"](#socket/3-common-configuration) and ["WebSocket configuration"](#socket/3-websocket-configuration) for the whole list * `:longpoll` - controls the longpoll configuration. Defaults to `false`. May be true or a keyword list of options. See ["Common configuration"](#socket/3-common-configuration) and ["Longpoll configuration"](#socket/3-longpoll-configuration) for the whole list * `:drainer` - a keyword list or a custom MFA function returning a keyword list, for example: {MyAppWeb.Socket, :drainer_configuration, []} configuring how to drain sockets on application shutdown. The goal is to notify all channels (and LiveViews) clients to reconnect. The supported options are: * `:batch_size` - How many clients to notify at once in a given batch. Defaults to 10000. * `:batch_interval` - The amount of time in milliseconds given for a batch to terminate. Defaults to 2000ms. * `:shutdown` - The maximum amount of time in milliseconds allowed to drain all batches. Defaults to 30000ms. For example, if you have 150k connections, the default values will split them into 15 batches of 10k connections. Each batch takes 2000ms before the next batch starts. In this case, we will do everything right under the maximum shutdown time of 30000ms. Therefore, as you increase the number of connections, remember to adjust the shutdown accordingly. Finally, after the socket drainer runs, the lower level HTTP/HTTPS connection drainer will still run, and apply to all connections. Set it to `false` to disable draining. You can also pass the options below on `use Phoenix.Socket`. The values specified here override the value in `use Phoenix.Socket`. ### Examples - Phoenix.Endpoint.socket/3 (macro) socket "/ws", MyApp.UserSocket socket "/ws/admin", MyApp.AdminUserSocket, longpoll: true, websocket: [compress: true] ### Path params - Phoenix.Endpoint.socket/3 (macro) It is possible to include variables in the path, these will be available in the `params` that are passed to the socket. socket "/ws/:user_id", MyApp.UserSocket, websocket: [path: "/project/:project_id"] ### Common configuration - Phoenix.Endpoint.socket/3 (macro) The configuration below can be given to both `:websocket` and `:longpoll` keys: * `:path` - the path to use for the transport. Will default to the transport name ("/websocket" or "/longpoll") * `:serializer` - a list of serializers for messages. See `Phoenix.Socket` for more information * `:transport_log` - if the transport layer itself should log and, if so, the level * `:check_origin` - if the transport should check the origin of requests when the `origin` header is present. May be `true`, `false`, a list of hosts that are allowed, or a function provided as MFA tuple. Defaults to `:check_origin` setting at endpoint configuration. If `true`, the header is checked against `:host` in `YourAppWeb.Endpoint.config(:url)[:host]`. If `false` and you do not validate the session in your socket, your app is vulnerable to Cross-Site WebSocket Hijacking (CSWSH) attacks. Only use in development, when the host is truly unknown or when serving clients that do not send the `origin` header, such as mobile apps. You can also specify a list of explicitly allowed origins. Wildcards are supported. check_origin: [ "https://example.com", "//another.com:888", "//*.other.com" ] Or to accept any origin matching the request connection's host, port, and scheme: check_origin: :conn Or a custom MFA function: check_origin: {MyAppWeb.Auth, :my_check_origin?, []} The MFA is invoked with the request `%URI{}` as the first argument, followed by arguments in the MFA list, and must return a boolean. * `:code_reloader` - enable or disable the code reloader. Defaults to your endpoint configuration * `:connect_info` - a list of keys that represent data to be copied from the transport to be made available in the user socket `connect/3` callback. See the "Connect info" subsection for valid keys ### Connect info - Phoenix.Endpoint.socket/3 (macro) The valid keys are: * `:peer_data` - the result of `Plug.Conn.get_peer_data/1` * `:trace_context_headers` - a list of all trace context headers. Supported headers are defined by the [W3C Trace Context Specification](https://www.w3.org/TR/trace-context-1/). These headers are necessary for libraries such as [OpenTelemetry](https://opentelemetry.io/) to extract trace propagation information to know this request is part of a larger trace in progress. * `:x_headers` - all request headers that have an "x-" prefix * `:uri` - a `%URI{}` with information from the conn * `:user_agent` - the value of the "user-agent" request header * `{:session, session_config}` - the session information from `Plug.Conn`. The `session_config` is typically an exact copy of the arguments given to `Plug.Session`. In order to validate the session, the "_csrf_token" must be given as request parameter when connecting the socket with the value of `URI.encode_www_form(Plug.CSRFProtection.get_csrf_token())`. The CSRF token request parameter can be modified via the `:csrf_token_key` option. Additionally, `session_config` may be a MFA, such as `{MyAppWeb.Auth, :get_session_config, []}`, to allow loading config in runtime. Arbitrary keywords may also appear following the above valid keys, which is useful for passing custom connection information to the socket. For example: ``` socket "/socket", AppWeb.UserSocket, websocket: [ connect_info: [:peer_data, :trace_context_headers, :x_headers, :uri, session: [store: :cookie]] ] ``` With arbitrary keywords: ``` socket "/socket", AppWeb.UserSocket, websocket: [ connect_info: [:uri, custom_value: "abcdef"] ] ``` > #### Where are my headers? {: .tip} > > Phoenix only gives you limited access to the connection headers for security > reasons. WebSockets are cross-domain, which means that, when a user "John Doe" > visits a malicious website, the malicious website can open up a WebSocket > connection to your application, and the browser will gladly submit John Doe's > authentication/cookie information. If you were to accept this information as is, > the malicious website would have full control of a WebSocket connection to your > application, authenticated on John Doe's behalf. > > To safe-guard your application, Phoenix limits and validates the connection > information your socket can access. This means your application is safe from > these attacks, but you can't access cookies and other headers in your socket. > You may access the session stored in the connection via the `:connect_info` > option, provided you also pass a csrf token when connecting over WebSocket. ### Websocket configuration - Phoenix.Endpoint.socket/3 (macro) The following configuration applies only to `:websocket`. * `:timeout` - the timeout for keeping websocket connections open after it last received data, defaults to 60_000ms * `:max_frame_size` - the maximum allowed frame size in bytes, defaults to "infinity" * `:fullsweep_after` - the maximum number of garbage collections before forcing a fullsweep for the socket process. You can set it to `0` to force more frequent cleanups of your websocket transport processes. Setting this option requires Erlang/OTP 24 * `:compress` - whether to enable per message compression on all data frames, defaults to false * `:subprotocols` - a list of supported websocket subprotocols. Used for handshake `Sec-WebSocket-Protocol` response header, defaults to nil. For example: subprotocols: ["sip", "mqtt"] * `:error_handler` - custom error handler for connection errors. If `c:Phoenix.Socket.connect/3` returns an `{:error, reason}` tuple, the error handler will be called with the error reason. For WebSockets, the error handler must be a MFA tuple that receives a `Plug.Conn`, the error reason, and returns a `Plug.Conn` with a response. For example: socket "/socket", MySocket, websocket: [ error_handler: {MySocket, :handle_error, []} ] and a `{:error, :rate_limit}` return may be handled on `MySocket` as: def handle_error(conn, :rate_limit), do: Plug.Conn.send_resp(conn, 429, "Too many requests") ### Longpoll configuration - Phoenix.Endpoint.socket/3 (macro) The following configuration applies only to `:longpoll`: * `:window_ms` - how long the client can wait for new messages in its poll request in milliseconds (ms). Defaults to `10_000`. * `:pubsub_timeout_ms` - how long a request can wait for the pubsub layer to respond in milliseconds (ms). Defaults to `2000`. * `:crypto` - options for verifying and signing the token, accepted by `Phoenix.Token`. By default tokens are valid for 2 weeks ### Phoenix.Endpoint.start_link/1 (callback) Starts the endpoint supervision tree. Starts endpoint's configuration cache and possibly the servers for handling requests. ### Phoenix.Endpoint.static_integrity/1 (callback) Generates an integrity hash to a static file in `priv/static`. ### Phoenix.Endpoint.static_lookup/1 (callback) Generates a two item tuple containing the `static_path` and `static_integrity`. ### Phoenix.Endpoint.static_path/1 (callback) Generates a route to a static file in `priv/static`. ### Phoenix.Endpoint.static_url/0 (callback) Generates the static URL without any path information. ### Phoenix.Endpoint.struct_url/0 (callback) Generates the endpoint base URL, but as a `URI` struct. ### Phoenix.Endpoint.subscribe/2 (callback) Subscribes the caller to the given topic. See `Phoenix.PubSub.subscribe/3` for options. ### Phoenix.Endpoint.unsubscribe/1 (callback) Unsubscribes the caller from the given topic. ### Phoenix.Endpoint.url/0 (callback) Generates the endpoint base URL without any path information. ### Phoenix.Endpoint.event/0 (type) ### Phoenix.Endpoint.msg/0 (type) ### Phoenix.Endpoint.topic/0 (type) ### Phoenix.Flash (module) Provides shared flash access. ### Phoenix.Flash.get/2 (function) Gets the key from the map of flash data. ### Examples - Phoenix.Flash.get/2 (function) <%= Phoenix.Flash.get(@flash, :info) %> <%= Phoenix.Flash.get(@flash, :error) %> ### Phoenix.Logger (module) Instrumenter to handle logging of various instrumentation events. ### Instrumentation - Phoenix.Logger (module) Phoenix uses the `:telemetry` library for instrumentation. The following events are published by Phoenix with the following measurements and metadata: * `[:phoenix, :endpoint, :init]` - dispatched by `Phoenix.Endpoint` after your Endpoint supervision tree successfully starts * Measurement: `%{system_time: system_time}` * Metadata: `%{pid: pid(), config: Keyword.t(), module: module(), otp_app: atom()}` * Disable logging: This event is not logged * `[:phoenix, :endpoint, :start]` - dispatched by `Plug.Telemetry` in your endpoint, usually after code reloading * Measurement: `%{system_time: system_time}` * Metadata: `%{conn: Plug.Conn.t, options: Keyword.t}` * Options: `%{log: Logger.level | false}` * Disable logging: In your endpoint `plug Plug.Telemetry, ..., log: Logger.level | false` * Configure log level dynamically: `plug Plug.Telemetry, ..., log: {Mod, Fun, Args}` * `[:phoenix, :endpoint, :stop]` - dispatched by `Plug.Telemetry` in your endpoint whenever the response is sent * Measurement: `%{duration: native_time}` * Metadata: `%{conn: Plug.Conn.t, options: Keyword.t}` * Options: `%{log: Logger.level | false}` * Disable logging: In your endpoint `plug Plug.Telemetry, ..., log: Logger.level | false` * Configure log level dynamically: `plug Plug.Telemetry, ..., log: {Mod, Fun, Args}` * `[:phoenix, :router_dispatch, :start]` - dispatched by `Phoenix.Router` before dispatching to a matched route * Measurement: `%{system_time: System.system_time}` * Metadata: `%{conn: Plug.Conn.t, route: binary, plug: module, plug_opts: term, path_params: map, pipe_through: [atom], log: Logger.level | false}` * Disable logging: Pass `log: false` to the router macro, for example: `get("/page", PageController, :index, log: false)` * Configure log level dynamically: `get("/page", PageController, :index, log: {Mod, Fun, Args})` * `[:phoenix, :router_dispatch, :exception]` - dispatched by `Phoenix.Router` after exceptions on dispatching a route * Measurement: `%{duration: native_time}` * Metadata: `%{conn: Plug.Conn.t, kind: :throw | :error | :exit, reason: term(), stacktrace: Exception.stacktrace()}` * Disable logging: This event is not logged * `[:phoenix, :router_dispatch, :stop]` - dispatched by `Phoenix.Router` after successfully dispatching a matched route * Measurement: `%{duration: native_time}` * Metadata: `%{conn: Plug.Conn.t, route: binary, plug: module, plug_opts: term, path_params: map, pipe_through: [atom], log: Logger.level | false}` * Disable logging: This event is not logged * `[:phoenix, :error_rendered]` - dispatched at the end of an error view being rendered * Measurement: `%{duration: native_time}` * Metadata: `%{conn: Plug.Conn.t, status: Plug.Conn.status, kind: Exception.kind, reason: term, stacktrace: Exception.stacktrace}` * Disable logging: Set `render_errors: [log: false]` on your endpoint configuration * `[:phoenix, :socket_connected]` - dispatched by `Phoenix.Socket`, at the end of a socket connection * Measurement: `%{duration: native_time}` * Metadata: `%{endpoint: atom, transport: atom, params: term, connect_info: map, vsn: binary, user_socket: atom, result: :ok | :error, serializer: atom, log: Logger.level | false}` * Disable logging: `use Phoenix.Socket, log: false` or `socket "/foo", MySocket, websocket: [log: false]` in your endpoint * `[:phoenix, :channel_joined]` - dispatched at the end of a channel join * Measurement: `%{duration: native_time}` * Metadata: `%{result: :ok | :error, params: term, socket: Phoenix.Socket.t}` * Disable logging: This event cannot be disabled * `[:phoenix, :channel_handled_in]` - dispatched at the end of a channel handle in * Measurement: `%{duration: native_time}` * Metadata: `%{event: binary, params: term, socket: Phoenix.Socket.t}` * Disable logging: This event cannot be disabled To see an example of how Phoenix LiveDashboard uses these events to create metrics, visit . ### Parameter filtering - Phoenix.Logger (module) When logging parameters, Phoenix can filter out sensitive parameters such as passwords and tokens. Parameters to be filtered can be added via the `:filter_parameters` option: config :phoenix, :filter_parameters, ["password", "secret"] With the configuration above, Phoenix will filter any parameter that contains the terms `password` or `secret`. The match is case sensitive. Phoenix's default is `["password"]`. Phoenix can filter all parameters by default and selectively keep parameters. This can be configured like so: config :phoenix, :filter_parameters, {:keep, ["id", "order"]} With the configuration above, Phoenix will filter all parameters, except those that match exactly `id` or `order`. If a kept parameter matches, all parameters nested under that one will also be kept. ### Dynamic log level - Phoenix.Logger (module) In some cases you may wish to set the log level dynamically on a per-request basis. To do so, set the `:log` option to a tuple, `{Mod, Fun, Args}`. The `Plug.Conn.t()` for the request will be prepended to the provided list of arguments. When invoked, your function must return a [`Logger.level()`](`t:Logger.level()/0`) or `false` to disable logging for the request. For example, in your Endpoint you might do something like this: # lib/my_app_web/endpoint.ex plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint], log: {__MODULE__, :log_level, []} # Disables logging for routes like /status/* def log_level(%{path_info: ["status" | _]}), do: false def log_level(_), do: :info ### Disabling - Phoenix.Logger (module) When you are using custom logging system it is not always desirable to enable `Phoenix.Logger` by default. You can always disable this in general by: config :phoenix, :logger, false ### Phoenix.Naming (module) Conveniences for inflecting and working with names in Phoenix. ### Phoenix.Naming.camelize/1 (function) Converts a string to camel case. Takes an optional `:lower` flag to return lowerCamelCase. ### Examples - Phoenix.Naming.camelize/1 (function) iex> Phoenix.Naming.camelize("my_app") "MyApp" iex> Phoenix.Naming.camelize("my_app", :lower) "myApp" In general, `camelize` can be thought of as the reverse of `underscore`, however, in some cases formatting may be lost: Phoenix.Naming.underscore "SAPExample" #=> "sap_example" Phoenix.Naming.camelize "sap_example" #=> "SapExample" ### Phoenix.Naming.camelize/2 (function) ### Phoenix.Naming.humanize/1 (function) Converts an attribute/form field into its humanize version. ### Examples - Phoenix.Naming.humanize/1 (function) iex> Phoenix.Naming.humanize(:username) "Username" iex> Phoenix.Naming.humanize(:created_at) "Created at" iex> Phoenix.Naming.humanize("user_id") "User" ### Phoenix.Naming.resource_name/2 (function) Extracts the resource name from an alias. ### Examples - Phoenix.Naming.resource_name/2 (function) iex> Phoenix.Naming.resource_name(MyApp.User) "user" iex> Phoenix.Naming.resource_name(MyApp.UserView, "View") "user" ### Phoenix.Naming.underscore/1 (function) Converts a string to underscore case. ### Examples - Phoenix.Naming.underscore/1 (function) iex> Phoenix.Naming.underscore("MyApp") "my_app" In general, `underscore` can be thought of as the reverse of `camelize`, however, in some cases formatting may be lost: Phoenix.Naming.underscore "SAPExample" #=> "sap_example" Phoenix.Naming.camelize "sap_example" #=> "SapExample" ### Phoenix.Naming.unsuffix/2 (function) Removes the given suffix from the name if it exists. ### Examples - Phoenix.Naming.unsuffix/2 (function) iex> Phoenix.Naming.unsuffix("MyApp.User", "View") "MyApp.User" iex> Phoenix.Naming.unsuffix("MyApp.UserView", "View") "MyApp.User" ### Phoenix.Param (protocol) A protocol that converts data structures into URL parameters. This protocol is used by URL helpers and other parts of the Phoenix stack. For example, when you write: user_path(conn, :edit, @user) Phoenix knows how to extract the `:id` from `@user` thanks to this protocol. By default, Phoenix implements this protocol for integers, binaries, atoms, and structs. For structs, a key `:id` is assumed, but you may provide a specific implementation. Nil values cannot be converted to param. ### Custom parameters - Phoenix.Param (protocol) In order to customize the parameter for any struct, one can simply implement this protocol. However, for convenience, this protocol can also be derivable. For example: defmodule User do @derive Phoenix.Param defstruct [:id, :username] end By default, the derived implementation will also use the `:id` key. In case the user does not contain an `:id` key, the key can be specified with an option: defmodule User do @derive {Phoenix.Param, key: :username} defstruct [:username] end will automatically use `:username` in URLs. When using Ecto, you must call `@derive` before your `schema` call: @derive {Phoenix.Param, key: :username} schema "users" do ### Phoenix.Param.to_param/1 (function) ### Phoenix.Param.t/0 (type) All the types that implement this protocol. ### Phoenix.Presence (behaviour) Provides Presence tracking to processes and channels. This behaviour provides presence features such as fetching presences for a given topic, as well as handling diffs of join and leave events as they occur in real-time. Using this module defines a supervisor and a module that implements the `Phoenix.Tracker` behaviour that uses `Phoenix.PubSub` to broadcast presence updates. In case you want to use only a subset of the functionality provided by `Phoenix.Presence`, such as tracking processes but without broadcasting updates, we recommend that you look at the `Phoenix.Tracker` functionality from the `phoenix_pubsub` project. ### Example Usage - Phoenix.Presence (behaviour) Start by defining a presence module within your application which uses `Phoenix.Presence` and provide the `:otp_app` which holds your configuration, as well as the `:pubsub_server`. defmodule MyAppWeb.Presence do use Phoenix.Presence, otp_app: :my_app, pubsub_server: MyApp.PubSub end The `:pubsub_server` must point to an existing pubsub server running in your application, which is included by default as `MyApp.PubSub` for new applications. Next, add the new supervisor to your supervision tree in `lib/my_app/application.ex`. It must be after the PubSub child and before the endpoint: children = [ ... {Phoenix.PubSub, name: MyApp.PubSub}, MyAppWeb.Presence, MyAppWeb.Endpoint ] Once added, presences can be tracked in your channel after joining: defmodule MyAppWeb.MyChannel do use MyAppWeb, :channel alias MyAppWeb.Presence def join("some:topic", _params, socket) do send(self(), :after_join) {:ok, assign(socket, :user_id, ...)} end def handle_info(:after_join, socket) do {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{ online_at: inspect(System.system_time(:second)) }) push(socket, "presence_state", Presence.list(socket)) {:noreply, socket} end end In the example above, `Presence.track` is used to register this channel's process as a presence for the socket's user ID, with a map of metadata. Next, the current presence information for the socket's topic is pushed to the client as a `"presence_state"` event. Finally, a diff of presence join and leave events will be sent to the client as they happen in real-time with the "presence_diff" event. The diff structure will be a map of `:joins` and `:leaves` of the form: %{ joins: %{"123" => %{metas: [%{status: "away", phx_ref: ...}]}}, leaves: %{"456" => %{metas: [%{status: "online", phx_ref: ...}]}} }, See `c:list/1` for more information on the presence data structure. ### Fetching Presence Information - Phoenix.Presence (behaviour) Presence metadata should be minimized and used to store small, ephemeral state, such as a user's "online" or "away" status. More detailed information, such as user details that need to be fetched from the database, can be achieved by overriding the `c:fetch/2` function. The `c:fetch/2` callback is triggered when using `c:list/1` and on every update, and it serves as a mechanism to fetch presence information a single time, before broadcasting the information to all channel subscribers. This prevents N query problems and gives you a single place to group isolated data fetching to extend presence metadata. The function must return a map of data matching the outlined Presence data structure, including the `:metas` key, but can extend the map of information to include any additional information. For example: def fetch(_topic, presences) do users = presences |> Map.keys() |> Accounts.get_users_map() for {key, %{metas: metas}} <- presences, into: %{} do {key, %{metas: metas, user: users[String.to_integer(key)]}} end end Where `Account.get_users_map/1` could be implemented like: def get_users_map(ids) do query = from u in User, where: u.id in ^ids, select: {u.id, u} query |> Repo.all() |> Enum.into(%{}) end The `fetch/2` function above fetches all users from the database who have registered presences for the given topic. The presences information is then extended with a `:user` key of the user's information, while maintaining the required `:metas` field from the original presence data. ### Using Elixir as a Presence Client - Phoenix.Presence (behaviour) Presence is great for external clients, such as JavaScript applications, but it can also be used from an Elixir client process to keep track of presence changes as they happen on the server. This can be accomplished by implementing the optional [`init/1`](`c:init/1`) and [`handle_metas/4`](`c:handle_metas/4`) callbacks on your presence module. For example, the following callback receives presence metadata changes, and broadcasts to other Elixir processes about users joining and leaving: defmodule MyApp.Presence do use Phoenix.Presence, otp_app: :my_app, pubsub_server: MyApp.PubSub def init(_opts) do {:ok, %{}} # user-land state end def handle_metas(topic, %{joins: joins, leaves: leaves}, presences, state) do # fetch existing presence information for the joined users and broadcast the # event to all subscribers for {user_id, presence} <- joins do user_data = %{user: presence.user, metas: Map.fetch!(presences, user_id)} msg = {MyApp.PresenceClient, {:join, user_data}} Phoenix.PubSub.local_broadcast(MyApp.PubSub, topic, msg) end # fetch existing presence information for the left users and broadcast the # event to all subscribers for {user_id, presence} <- leaves do metas = case Map.fetch(presences, user_id) do {:ok, presence_metas} -> presence_metas :error -> [] end user_data = %{user: presence.user, metas: metas} msg = {MyApp.PresenceClient, {:leave, user_data}} Phoenix.PubSub.local_broadcast(MyApp.PubSub, topic, msg) end {:ok, state} end end The `handle_metas/4` callback receives the topic, presence diff, current presences for the topic with their metadata, and any user-land state accumulated from init and subsequent `handle_metas/4` calls. In our example implementation, we walk the `:joins` and `:leaves` in the diff, and populate a complete presence from our known presence information. Then we broadcast to the local node subscribers about user joins and leaves. ### Testing with Presence - Phoenix.Presence (behaviour) Every time the `fetch` callback is invoked, it is done from a separate process. Given those processes run asynchronously, it is often necessary to guarantee they have been shutdown at the end of every test. This can be done by using ExUnit's `on_exit` hook plus `fetchers_pids` function: on_exit(fn -> for pid <- MyAppWeb.Presence.fetchers_pids() do ref = Process.monitor(pid) assert_receive {:DOWN, ^ref, _, _, _}, 1000 end end) ### Phoenix.Presence.fetch/2 (callback) Extend presence information with additional data. When `c:list/1` is used to list all presences of the given `topic`, this callback is triggered once to modify the result before it is broadcasted to all channel subscribers. This avoids N query problems and provides a single place to extend presence metadata. You must return a map of data matching the original result, including the `:metas` key, but can extend the map to include any additional information. The default implementation simply passes `presences` through unchanged. ### Example - Phoenix.Presence.fetch/2 (callback) def fetch(_topic, presences) do query = from u in User, where: u.id in ^Map.keys(presences), select: {u.id, u} users = query |> Repo.all() |> Enum.into(%{}) for {key, %{metas: metas}} <- presences, into: %{} do {key, %{metas: metas, user: users[key]}} end end ### Phoenix.Presence.get_by_key/2 (callback) Returns the map of presence metadata for a socket/topic-key pair. ### Examples - Phoenix.Presence.get_by_key/2 (callback) Uses the same data format as each presence in `c:list/1`, but only returns metadata for the presences under a topic and key pair. For example, a user with key `"user1"`, connected to the same chat room `"room:1"` from two devices, could return: iex> MyPresence.get_by_key("room:1", "user1") [%{name: "User 1", metas: [%{device: "Desktop"}, %{device: "Mobile"}]}] Like `c:list/1`, the presence metadata is passed to the `fetch` callback of your presence module to fetch any additional information. ### Phoenix.Presence.handle_metas/4 (callback) Receives presence metadata changes. ### Phoenix.Presence.init/1 (callback) Initializes the presence client state. Invoked when your presence module starts, allows dynamically providing initial state for handling presence metadata. ### Phoenix.Presence.list/1 (callback) Returns presences for a socket/topic. ### Presence data structure - Phoenix.Presence.list/1 (callback) The presence information is returned as a map with presences grouped by key, cast as a string, and accumulated metadata, with the following form: %{key => %{metas: [%{phx_ref: ..., ...}, ...]}} For example, imagine a user with id `123` online from two different devices, as well as a user with id `456` online from just one device. The following presence information might be returned: %{"123" => %{metas: [%{status: "away", phx_ref: ...}, %{status: "online", phx_ref: ...}]}, "456" => %{metas: [%{status: "online", phx_ref: ...}]}} The keys of the map will usually point to a resource ID. The value will contain a map with a `:metas` key containing a list of metadata for each resource. Additionally, every metadata entry will contain a `:phx_ref` key which can be used to uniquely identify metadata for a given key. In the event that the metadata was previously updated, a `:phx_ref_prev` key will be present containing the previous `:phx_ref` value. ### Phoenix.Presence.track/3 (callback) Track a channel's process as a presence. Tracked presences are grouped by `key`, cast as a string. For example, to group each user's channels together, use user IDs as keys. Each presence can be associated with a map of metadata to store small, ephemeral state, such as a user's online status. To store detailed information, see `c:fetch/2`. ### Example - Phoenix.Presence.track/3 (callback) alias MyApp.Presence def handle_info(:after_join, socket) do {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{ online_at: inspect(System.system_time(:second)) }) {:noreply, socket} end ### Phoenix.Presence.track/4 (callback) Track an arbitrary process as a presence. Same with `track/3`, except track any process by `topic` and `key`. ### Phoenix.Presence.untrack/2 (callback) Stop tracking a channel's process. ### Phoenix.Presence.untrack/3 (callback) Stop tracking a process. ### Phoenix.Presence.update/3 (callback) Update a channel presence's metadata. Replace a presence's metadata by passing a new map or a function that takes the current map and returns a new one. ### Phoenix.Presence.update/4 (callback) Update a process presence's metadata. Same as `update/3`, but with an arbitrary process. ### Phoenix.Presence.presence/0 (type) ### Phoenix.Presence.presences/0 (type) ### Phoenix.Presence.topic/0 (type) ### Phoenix.Router (module) Defines a Phoenix router. The router provides a set of macros for generating routes that dispatch to specific controllers and actions. Those macros are named after HTTP verbs. For example: defmodule MyAppWeb.Router do use Phoenix.Router get "/pages/:page", PageController, :show end The `get/3` macro above accepts a request to `/pages/hello` and dispatches it to `PageController`'s `show` action with `%{"page" => "hello"}` in `params`. Phoenix's router is extremely efficient, as it relies on Elixir pattern matching for matching routes and serving requests. ### Routing - Phoenix.Router (module) `get/3`, `post/3`, `put/3`, and other macros named after HTTP verbs are used to create routes. The route: get "/pages", PageController, :index matches a `GET` request to `/pages` and dispatches it to the `index` action in `PageController`. get "/pages/:page", PageController, :show matches `/pages/hello` and dispatches to the `show` action with `%{"page" => "hello"}` in `params`. defmodule PageController do def show(conn, params) do # %{"page" => "hello"} == params end end Partial and multiple segments can be matched. For example: get "/api/v:version/pages/:id", PageController, :show matches `/api/v1/pages/2` and puts `%{"version" => "1", "id" => "2"}` in `params`. Only the trailing part of a segment can be captured. Routes are matched from top to bottom. The second route here: get "/pages/:page", PageController, :show get "/pages/hello", PageController, :hello will never match `/pages/hello` because `/pages/:page` matches that first. Routes can use glob-like patterns to match trailing segments. get "/pages/*page", PageController, :show matches `/pages/hello/world` and puts the globbed segments in `params["page"]`. GET /pages/hello/world %{"page" => ["hello", "world"]} = params Globs cannot have prefixes nor suffixes, but can be mixed with variables: get "/pages/he:page/*rest", PageController, :show matches GET /pages/hello %{"page" => "llo", "rest" => []} = params GET /pages/hey/there/world %{"page" => "y", "rest" => ["there" "world"]} = params > #### Why the macros? {: .info} > > Phoenix does its best to keep the usage of macros low. You may have noticed, > however, that the `Phoenix.Router` relies heavily on macros. Why is that? > > We use `get`, `post`, `put`, and `delete` to define your routes. We use macros > for two purposes: > > * They define the routing engine, used on every request, to choose which > controller to dispatch the request to. Thanks to macros, Phoenix compiles > all of your routes to a single case-statement with pattern matching rules, > which is heavily optimized by the Erlang VM > > * For each route you define, we also define metadata to implement `Phoenix.VerifiedRoutes`. > As we will soon learn, verified routes allows to us to reference any route > as if it is a plain looking string, except it is verified by the compiler > to be valid (making it much harder to ship broken links, forms, mails, etc > to production) > > In other words, the router relies on macros to build applications that are > faster and safer. Also remember that macros in Elixir are compile-time only, > which gives plenty of stability after the code is compiled. Phoenix also provides > introspection for all defined routes via `mix phx.routes`. ### Generating routes - Phoenix.Router (module) For generating routes inside your application, see the `Phoenix.VerifiedRoutes` documentation for `~p` based route generation which is the preferred way to generate route paths and URLs with compile-time verification. Phoenix also supports generating function helpers, which was the default mechanism in Phoenix v1.6 and earlier. We will explore it next. ### Helpers (deprecated) - Phoenix.Router (module) Phoenix generates a module `Helpers` inside your router by default, which contains named helpers to help developers generate and keep their routes up to date. Helpers can be disabled by passing `helpers: false` to `use Phoenix.Router`. Helpers are automatically generated based on the controller name. For example, the route: get "/pages/:page", PageController, :show will generate the following named helper: MyAppWeb.Router.Helpers.page_path(conn_or_endpoint, :show, "hello") "/pages/hello" MyAppWeb.Router.Helpers.page_path(conn_or_endpoint, :show, "hello", some: "query") "/pages/hello?some=query" MyAppWeb.Router.Helpers.page_url(conn_or_endpoint, :show, "hello") "http://example.com/pages/hello" MyAppWeb.Router.Helpers.page_url(conn_or_endpoint, :show, "hello", some: "query") "http://example.com/pages/hello?some=query" If the route contains glob-like patterns, parameters for those have to be given as list: MyAppWeb.Router.Helpers.page_path(conn_or_endpoint, :show, ["hello", "world"]) "/pages/hello/world" The URL generated in the named URL helpers is based on the configuration for `:url`, `:http` and `:https`. However, if for some reason you need to manually control the URL generation, the url helpers also allow you to pass in a `URI` struct: uri = %URI{scheme: "https", host: "other.example.com"} MyAppWeb.Router.Helpers.page_url(uri, :show, "hello") "https://other.example.com/pages/hello" The named helper can also be customized with the `:as` option. Given the route: get "/pages/:page", PageController, :show, as: :special_page the named helper will be: MyAppWeb.Router.Helpers.special_page_path(conn, :show, "hello") "/pages/hello" ### Scopes and Resources - Phoenix.Router (module) It is very common in Phoenix applications to namespace all of your routes under the application scope: scope "/", MyAppWeb do get "/pages/:id", PageController, :show end The route above will dispatch to `MyAppWeb.PageController`. This syntax is not only convenient for developers, since we don't have to repeat the `MyAppWeb.` prefix on all routes, but it also allows Phoenix to put less pressure on the Elixir compiler. If instead we had written: get "/pages/:id", MyAppWeb.PageController, :show The Elixir compiler would infer that the router depends directly on `MyAppWeb.PageController`, which is not true. By using scopes, Phoenix can properly hint to the Elixir compiler the controller is not an actual dependency of the router. This provides more efficient compilation times. Scopes allow us to scope on any path or even on the helper name: scope "/v1", MyAppWeb, host: "api." do get "/pages/:id", PageController, :show end For example, the route above will match on the path `"/api/v1/pages/1"` and the named route will be `api_v1_page_path`, as expected from the values given to `scope/2` option. Like all paths you can define dynamic segments that will be applied as parameters in the controller: scope "/api/:version", MyAppWeb do get "/pages/:id", PageController, :show end For example, the route above will match on the path `"/api/v1/pages/1"` and in the controller the `params` argument will have a map with the key `:version` with the value `"v1"`. Phoenix also provides a `resources/4` macro that allows developers to generate "RESTful" routes to a given resource: defmodule MyAppWeb.Router do use Phoenix.Router resources "/pages", PageController, only: [:show] resources "/users", UserController, except: [:delete] end Finally, Phoenix ships with a `mix phx.routes` task that nicely formats all routes in a given router. We can use it to verify all routes included in the router above: $ mix phx.routes page_path GET /pages/:id PageController.show/2 user_path GET /users UserController.index/2 user_path GET /users/:id/edit UserController.edit/2 user_path GET /users/new UserController.new/2 user_path GET /users/:id UserController.show/2 user_path POST /users UserController.create/2 user_path PATCH /users/:id UserController.update/2 PUT /users/:id UserController.update/2 One can also pass a router explicitly as an argument to the task: $ mix phx.routes MyAppWeb.Router Check `scope/2` and `resources/4` for more information. ### Pipelines and plugs - Phoenix.Router (module) Once a request arrives at the Phoenix router, it performs a series of transformations through pipelines until the request is dispatched to a desired route. Such transformations are defined via plugs, as defined in the [Plug](https://github.com/elixir-lang/plug) specification. Once a pipeline is defined, it can be piped through per scope. For example: defmodule MyAppWeb.Router do use Phoenix.Router pipeline :browser do plug :fetch_session plug :accepts, ["html"] end scope "/" do pipe_through :browser # browser related routes and resources end end `Phoenix.Router` imports functions from both `Plug.Conn` and `Phoenix.Controller` to help define plugs. In the example above, `fetch_session/2` comes from `Plug.Conn` while `accepts/2` comes from `Phoenix.Controller`. Note that router pipelines are only invoked after a route is found. No plug is invoked in case no matches were found. ### How to organize my routes? - Phoenix.Router (module) In Phoenix, we tend to define several pipelines, that provide specific functionality. For example, the `pipeline :browser` above includes plugs that are common for all routes that are meant to be accessed by a browser. Similarly, if you are also serving `:api` requests, you would have a separate `:api` pipeline that validates information specific to your endpoints. Perhaps more importantly, it is also very common to define pipelines specific to authentication and authorization. For example, you might have a pipeline that requires all users are authenticated. Another pipeline may enforce only admin users can access certain routes. Since routes are matched top to bottom, it is recommended to place the authenticated/authorized routes before the less restricted routes to ensure they are matched first. Once your pipelines are defined, you reuse the pipelines in the desired scopes, grouping your routes around their pipelines. For example, imagine you are building a blog. Anyone can read a post, but only authenticated users can create them. Your routes could look like this: pipeline :browser do plug :fetch_session plug :accepts, ["html"] end pipeline :auth do plug :ensure_authenticated end scope "/" do pipe_through [:browser, :auth] get "/posts/new", PostController, :new post "/posts", PostController, :create end scope "/" do pipe_through [:browser] get "/posts", PostController, :index get "/posts/:id", PostController, :show end Note in the above how the routes are split across different scopes. While the separation can be confusing at first, it has one big upside: it is very easy to inspect your routes and see all routes that, for example, require authentication and which ones do not. This helps with auditing and making sure your routes have the proper scope. You can create as few or as many scopes as you want. Because pipelines are reusable across scopes, they help encapsulate common functionality and you can compose them as necessary on each scope you define. ### Phoenix.Router.connect/4 (macro) Generates a route to handle a connect request to the given path. connect("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.delete/4 (macro) Generates a route to handle a delete request to the given path. delete("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.forward/4 (macro) Forwards a request at the given path to a plug. All paths that match the forwarded prefix will be sent to the forwarded plug. This is useful for sharing a router between applications or even breaking a big router into smaller ones. The router pipelines will be invoked prior to forwarding the connection. However, we don't advise forwarding to another endpoint. The reason is that plugs defined by your app and the forwarded endpoint would be invoked twice, which may lead to errors. ### Examples - Phoenix.Router.forward/4 (macro) scope "/", MyApp do pipe_through [:browser, :admin] forward "/admin", SomeLib.AdminDashboard forward "/api", ApiRouter end ### Phoenix.Router.get/4 (macro) Generates a route to handle a get request to the given path. get("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.head/4 (macro) Generates a route to handle a head request to the given path. head("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.match/5 (macro) Generates a route match based on an arbitrary HTTP method. Useful for defining routes not included in the built-in macros. The catch-all verb, `:*`, may also be used to match all HTTP methods. ### Options - Phoenix.Router.match/5 (macro) * `:as` - configures the named helper. If `nil`, does not generate a helper. Has no effect when using verified routes exclusively * `:alias` - configure if the scope alias should be applied to the route. Defaults to true, disables scoping if false. * `:log` - the level to log the route dispatching under, may be set to false. Defaults to `:debug`. Route dispatching contains information about how the route is handled (which controller action is called, what parameters are available and which pipelines are used) and is separate from the plug level logging. To alter the plug log level, please see https://hexdocs.pm/phoenix/Phoenix.Logger.html#module-dynamic-log-level. * `:private` - a map of private data to merge into the connection when a route matches * `:assigns` - a map of data to merge into the connection when a route matches * `:metadata` - a map of metadata used by the telemetry events and returned by `route_info/4` * `:warn_on_verify` - the boolean for whether matches to this route trigger an unmatched route warning for `Phoenix.VerifiedRoutes`. It is useful to ignore an otherwise catch-all route definition from being matched when verifying routes. Defaults `false`. ### Examples - Phoenix.Router.match/5 (macro) match(:move, "/events/:id", EventController, :move) match(:*, "/any", SomeController, :any) ### Phoenix.Router.options/4 (macro) Generates a route to handle a options request to the given path. options("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.patch/4 (macro) Generates a route to handle a patch request to the given path. patch("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.pipe_through/1 (macro) Defines a list of plugs (and pipelines) to send the connection through. Plugs are specified using the atom name of any imported 2-arity function which takes a `%Plug.Conn{}` and options and returns a `%Plug.Conn{}`; for example, `:require_authenticated_user`. Pipelines are defined in the router; see `pipeline/2` for more information. pipe_through [:my_imported_function, :my_pipeline] ### Phoenix.Router.pipeline/2 (macro) Defines a plug pipeline. Pipelines are defined at the router root and can be used from any scope. ### Examples - Phoenix.Router.pipeline/2 (macro) pipeline :api do plug :token_authentication plug :dispatch end A scope may then use this pipeline as: scope "/" do pipe_through :api end Every time `pipe_through/1` is called, the new pipelines are appended to the ones previously given. ### Phoenix.Router.plug/2 (macro) Defines a plug inside a pipeline. See `pipeline/2` for more information. ### Phoenix.Router.post/4 (macro) Generates a route to handle a post request to the given path. post("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.put/4 (macro) Generates a route to handle a put request to the given path. put("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Router.resources/2 (macro) See `resources/4`. ### Phoenix.Router.resources/3 (macro) See `resources/4`. ### Phoenix.Router.resources/4 (macro) Defines "RESTful" routes for a resource. The given definition: resources "/users", UserController will include routes to the following actions: * `GET /users` => `:index` * `GET /users/new` => `:new` * `POST /users` => `:create` * `GET /users/:id` => `:show` * `GET /users/:id/edit` => `:edit` * `PATCH /users/:id` => `:update` * `PUT /users/:id` => `:update` * `DELETE /users/:id` => `:delete` ### Options - Phoenix.Router.resources/4 (macro) This macro accepts a set of options: * `:only` - a list of actions to generate routes for, for example: `[:show, :edit]` * `:except` - a list of actions to exclude generated routes from, for example: `[:delete]` * `:param` - the name of the parameter for this resource, defaults to `"id"` * `:name` - the prefix for this resource. This is used for the named helper and as the prefix for the parameter in nested resources. The default value is automatically derived from the controller name, i.e. `UserController` will have name `"user"` * `:as` - configures the named helper. If `nil`, does not generate a helper. Has no effect when using verified routes exclusively * `:singleton` - defines routes for a singleton resource that is looked up by the client without referencing an ID. Read below for more information ### Singleton resources - Phoenix.Router.resources/4 (macro) When a resource needs to be looked up without referencing an ID, because it contains only a single entry in the given context, the `:singleton` option can be used to generate a set of routes that are specific to such single resource: * `GET /user` => `:show` * `GET /user/new` => `:new` * `POST /user` => `:create` * `GET /user/edit` => `:edit` * `PATCH /user` => `:update` * `PUT /user` => `:update` * `DELETE /user` => `:delete` Usage example: resources "/account", AccountController, only: [:show], singleton: true ### Nested Resources - Phoenix.Router.resources/4 (macro) This macro also supports passing a nested block of route definitions. This is helpful for nesting children resources within their parents to generate nested routes. The given definition: resources "/users", UserController do resources "/posts", PostController end will include the following routes: user_post_path GET /users/:user_id/posts PostController :index user_post_path GET /users/:user_id/posts/:id/edit PostController :edit user_post_path GET /users/:user_id/posts/new PostController :new user_post_path GET /users/:user_id/posts/:id PostController :show user_post_path POST /users/:user_id/posts PostController :create user_post_path PATCH /users/:user_id/posts/:id PostController :update PUT /users/:user_id/posts/:id PostController :update user_post_path DELETE /users/:user_id/posts/:id PostController :delete ### Phoenix.Router.route_info/4 (function) Returns the compile-time route info and runtime path params for a request. The `path` can be either a string or the `path_info` segments. A map of metadata is returned with the following keys: * `:log` - the configured log level. For example `:debug` * `:path_params` - the map of runtime path params * `:pipe_through` - the list of pipelines for the route's scope, for example `[:browser]` * `:plug` - the plug to dispatch the route to, for example `AppWeb.PostController` * `:plug_opts` - the options to pass when calling the plug, for example: `:index` * `:route` - the string route pattern, such as `"/posts/:id"` ### Examples - Phoenix.Router.route_info/4 (function) iex> Phoenix.Router.route_info(AppWeb.Router, "GET", "/posts/123", "myhost") %{ log: :debug, path_params: %{"id" => "123"}, pipe_through: [:browser], plug: AppWeb.PostController, plug_opts: :show, route: "/posts/:id", } iex> Phoenix.Router.route_info(MyRouter, "GET", "/not-exists", "myhost") :error ### Phoenix.Router.routes/1 (function) Returns all routes information from the given router. ### Phoenix.Router.scope/2 (macro) Defines a scope in which routes can be nested. ### Examples - Phoenix.Router.scope/2 (macro) scope path: "/api/v1", alias: API.V1 do get "/pages/:id", PageController, :show end The generated route above will match on the path `"/api/v1/pages/:id"` and will dispatch to `:show` action in `API.V1.PageController`. A named helper `api_v1_page_path` will also be generated. ### Options - Phoenix.Router.scope/2 (macro) The supported options are: * `:path` - a string containing the path scope. * `:as` - a string or atom containing the named helper scope. When set to false, it resets the nested helper scopes. Has no effect when using verified routes exclusively * `:alias` - an alias (atom) containing the controller scope. When set to false, it resets all nested aliases. * `:host` - a string or list of strings containing the host scope, or prefix host scope, ie `"foo.bar.com"`, `"foo."` * `:private` - a map of private data to merge into the connection when a route matches * `:assigns` - a map of data to merge into the connection when a route matches * `:log` - the level to log the route dispatching under, may be set to false. Defaults to `:debug`. Route dispatching contains information about how the route is handled (which controller action is called, what parameters are available and which pipelines are used) and is separate from the plug level logging. To alter the plug log level, please see https://hexdocs.pm/phoenix/Phoenix.Logger.html#module-dynamic-log-level. ### Phoenix.Router.scope/3 (macro) Define a scope with the given path. This function is a shortcut for: scope path: path do ... end ### Examples - Phoenix.Router.scope/3 (macro) scope "/v1", host: "api." do get "/pages/:id", PageController, :show end ### Phoenix.Router.scope/4 (macro) Defines a scope with the given path and alias. This function is a shortcut for: scope path: path, alias: alias do ... end ### Examples - Phoenix.Router.scope/4 (macro) scope "/v1", API.V1, host: "api." do get "/pages/:id", PageController, :show end ### Phoenix.Router.scoped_alias/2 (function) Returns the full alias with the current scope's aliased prefix. Useful for applying the same short-hand alias handling to other values besides the second argument in route definitions. ### Examples - Phoenix.Router.scoped_alias/2 (function) scope "/", MyPrefix do get "/", ProxyPlug, controller: scoped_alias(__MODULE__, MyController) end ### Phoenix.Router.scoped_path/2 (function) Returns the full path with the current scope's path prefix. ### Phoenix.Router.trace/4 (macro) Generates a route to handle a trace request to the given path. trace("/events/:id", EventController, :action) See `match/5` for options. ### Phoenix.Socket (behaviour) A socket implementation that multiplexes messages over channels. `Phoenix.Socket` is used as a module for establishing a connection between client and server. Once the connection is established, the initial state is stored in the `Phoenix.Socket` struct. The same socket can be used to receive events from different transports. Phoenix supports `websocket` and `longpoll` options when invoking `Phoenix.Endpoint.socket/3` in your endpoint. `websocket` is set by default and `longpoll` can also be configured explicitly. socket "/socket", MyAppWeb.Socket, websocket: true, longpoll: false The command above means incoming socket connections can be made via a WebSocket connection. Incoming and outgoing events are routed to channels by topic: channel "room:lobby", MyAppWeb.LobbyChannel See `Phoenix.Channel` for more information on channels. ### Socket Behaviour - Phoenix.Socket (behaviour) Socket handlers are mounted in Endpoints and must define two callbacks: * `connect/3` - receives the socket params, connection info if any, and authenticates the connection. Must return a `Phoenix.Socket` struct, often with custom assigns * `id/1` - receives the socket returned by `connect/3` and returns the id of this connection as a string. The `id` is used to identify socket connections, often to a particular user, allowing us to force disconnections. For sockets requiring no authentication, `nil` can be returned ### Examples - Phoenix.Socket (behaviour) defmodule MyAppWeb.UserSocket do use Phoenix.Socket channel "room:*", MyAppWeb.RoomChannel def connect(params, socket, _connect_info) do {:ok, assign(socket, :user_id, params["user_id"])} end def id(socket), do: "users_socket:#{socket.assigns.user_id}" end # Disconnect all user's socket connections and their multiplexed channels MyAppWeb.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{}) ### Socket fields - Phoenix.Socket (behaviour) * `:id` - The string id of the socket * `:assigns` - The map of socket assigns, default: `%{}` * `:channel` - The current channel module * `:channel_pid` - The channel pid * `:endpoint` - The endpoint module where this socket originated, for example: `MyAppWeb.Endpoint` * `:handler` - The socket module where this socket originated, for example: `MyAppWeb.UserSocket` * `:joined` - If the socket has effectively joined the channel * `:join_ref` - The ref sent by the client when joining * `:ref` - The latest ref sent by the client * `:pubsub_server` - The registered name of the socket's pubsub server * `:topic` - The string topic, for example `"room:123"` * `:transport` - An identifier for the transport, used for logging * `:transport_pid` - The pid of the socket's transport process * `:serializer` - The serializer for socket messages ### Using options - Phoenix.Socket (behaviour) On `use Phoenix.Socket`, the following options are accepted: * `:log` - the default level to log socket actions. Defaults to `:info`. May be set to `false` to disable it * `:partitions` - each channel is spawned under a supervisor. This option controls how many supervisors will be spawned to handle channels. Defaults to the number of cores. ### Garbage collection - Phoenix.Socket (behaviour) It's possible to force garbage collection in the transport process after processing large messages. For example, to trigger such from your channels, run: send(socket.transport_pid, :garbage_collect) Alternatively, you can configure your endpoint socket to trigger more fullsweep garbage collections more frequently, by setting the `:fullsweep_after` option for websockets. See `Phoenix.Endpoint.socket/3` for more info. ### Client-server communication - Phoenix.Socket (behaviour) The encoding of server data and the decoding of client data is done according to a serializer, defined in `Phoenix.Socket.Serializer`. By default, JSON encoding is used to broker messages to and from clients. The serializer `decode!` function must return a `Phoenix.Socket.Message` which is forwarded to channels except: * `"heartbeat"` events in the "phoenix" topic - should just emit an OK reply * `"phx_join"` on any topic - should join the topic * `"phx_leave"` on any topic - should leave the topic Each message also has a `ref` field which is used to track responses. The server may send messages or replies back. For messages, the ref uniquely identifies the message. For replies, the ref matches the original message. Both data-types also include a join_ref that uniquely identifies the currently joined channel. The `Phoenix.Socket` implementation may also send special messages and replies: * `"phx_error"` - in case of errors, such as a channel process crashing, or when attempting to join an already joined channel * `"phx_close"` - the channel was gracefully closed Phoenix ships with a JavaScript implementation of both websocket and long polling that interacts with Phoenix.Socket and can be used as reference for those interested in implementing custom clients. ### Custom sockets and transports - Phoenix.Socket (behaviour) See the `Phoenix.Socket.Transport` documentation for more information on writing your own socket that does not leverage channels or for writing your own transports that interacts with other sockets. ### Custom channels - Phoenix.Socket (behaviour) You can list any module as a channel as long as it implements a `child_spec/1` function. The `child_spec/1` function receives the caller as argument and it must return a child spec that initializes a process. Once the process is initialized, it will receive the following message: {Phoenix.Channel, auth_payload, from, socket} A custom channel implementation MUST invoke `GenServer.reply(from, {:ok | :error, reply_payload})` during its initialization with a custom `reply_payload` that will be sent as a reply to the client. Failing to do so will block the socket forever. A custom channel receives `Phoenix.Socket.Message` structs as regular messages from the transport. Replies to those messages and custom messages can be sent to the socket at any moment by building an appropriate `Phoenix.Socket.Reply` and `Phoenix.Socket.Message` structs, encoding them with the serializer and dispatching the serialized result to the transport. For example, to handle "phx_leave" messages, which is recommended to be handled by all channel implementations, one may do: def handle_info( %Message{topic: topic, event: "phx_leave"} = message, %{topic: topic, serializer: serializer, transport_pid: transport_pid} = socket ) do send transport_pid, serializer.encode!(build_leave_reply(message)) {:stop, {:shutdown, :left}, socket} end A special message delivered to all channels is a Broadcast with event "phx_drain", which is sent when draining the socket during application shutdown. Typically it is handled by sending a drain message to the transport, causing it to shutdown: def handle_info( %Broadcast{event: "phx_drain"}, %{transport_pid: transport_pid} = socket ) do send(transport_pid, :socket_drain) {:stop, {:shutdown, :draining}, socket} end We also recommend all channels to monitor the `transport_pid` on `init` and exit if the transport exits. We also advise to rewrite `:normal` exit reasons (usually due to the socket being closed) to the `{:shutdown, :closed}` to guarantee links are broken on the channel exit (as a `:normal` exit does not break links): def handle_info({:DOWN, _, _, transport_pid, reason}, %{transport_pid: transport_pid} = socket) do reason = if reason == :normal, do: {:shutdown, :closed}, else: reason {:stop, reason, socket} end Any process exit is treated as an error by the socket layer unless a `{:socket_close, pid, reason}` message is sent to the socket before shutdown. Custom channel implementations cannot be tested with `Phoenix.ChannelTest`. ### Phoenix.Socket.assign/2 (function) ### Phoenix.Socket.assign/3 (function) Adds key-value pairs to socket assigns. A single key-value pair may be passed, a keyword list or map of assigns may be provided to be merged into existing socket assigns. ### Examples - Phoenix.Socket.assign/3 (function) iex> assign(socket, :name, "Elixir") iex> assign(socket, name: "Elixir", logo: "💧") ### Phoenix.Socket.channel/3 (macro) Defines a channel matching the given topic and transports. * `topic_pattern` - The string pattern, for example `"room:*"`, `"users:*"`, or `"system"` * `module` - The channel module handler, for example `MyAppWeb.RoomChannel` * `opts` - The optional list of options, see below ### Options - Phoenix.Socket.channel/3 (macro) * `:assigns` - the map of socket assigns to merge into the socket on join ### Examples - Phoenix.Socket.channel/3 (macro) channel "topic1:*", MyChannel ### Topic Patterns - Phoenix.Socket.channel/3 (macro) The `channel` macro accepts topic patterns in two flavors. A splat (the `*` character) argument can be provided as the last character to indicate a `"topic:subtopic"` match. If a plain string is provided, only that topic will match the channel handler. Most use-cases will use the `"topic:*"` pattern to allow more versatile topic scoping. See `Phoenix.Channel` for more information ### Phoenix.Socket.connect/2 (callback) Shortcut version of `connect/3` which does not receive `connect_info`. Provided for backwards compatibility. ### Phoenix.Socket.connect/3 (callback) Receives the socket params and authenticates the connection. ### Socket params and assigns - Phoenix.Socket.connect/3 (callback) Socket params are passed from the client and can be used to verify and authenticate a user. After verification, you can put default assigns into the socket that will be set for all channels, ie {:ok, assign(socket, :user_id, verified_user_id)} To deny connection, return `:error` or `{:error, term}`. To control the response the client receives in that case, [define an error handler in the websocket configuration](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#socket/3-websocket-configuration). See `Phoenix.Token` documentation for examples in performing token verification on connect. ### Phoenix.Socket.id/1 (callback) Identifies the socket connection. Socket IDs are topics that allow you to identify all sockets for a given user: def id(socket), do: "users_socket:#{socket.assigns.user_id}" Would allow you to broadcast a `"disconnect"` event and terminate all active sockets and channels for a given user: MyAppWeb.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{}) Returning `nil` makes this socket anonymous. ### Phoenix.Socket.t/0 (type) ### Phoenix.Token (module) Conveniences to sign/encrypt data inside tokens for use in Channels, API authentication, and more. The data stored in the token is signed to prevent tampering, and is optionally encrypted. This means that, so long as the key (see below) remains secret, you can be assured that the data stored in the token has not been tampered with by a third party. However, unless the token is encrypted, it is not safe to use this token to store private information, such as a user's sensitive identification data, as it can be trivially decoded. If the token is encrypted, its contents will be kept secret from the client, but it is still a best practice to encode as little secret information as possible, to minimize the impact of key leakage. ### Example - Phoenix.Token (module) When generating a unique token for use in an API or Channel it is advised to use a unique identifier for the user, typically the id from a database. For example: iex> user_id = 1 iex> token = Phoenix.Token.sign(MyAppWeb.Endpoint, "user auth", user_id) iex> Phoenix.Token.verify(MyAppWeb.Endpoint, "user auth", token, max_age: 86400) {:ok, 1} In that example we have a user's id, we generate a token and verify it using the secret key base configured in the given `endpoint`. We guarantee the token will only be valid for one day by setting a max age (recommended). The first argument to `sign/4`, `verify/4`, `encrypt/4`, and `decrypt/4` can be one of: * the module name of a Phoenix endpoint (shown above) - where the secret key base is extracted from the endpoint * `Plug.Conn` - where the secret key base is extracted from the endpoint stored in the connection * `Phoenix.Socket` or `Phoenix.LiveView.Socket` - where the secret key base is extracted from the endpoint stored in the socket * a string, representing the secret key base itself. A key base with at least 20 randomly generated characters should be used to provide adequate entropy The second argument is a [cryptographic salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) which must be the same in both calls to `sign/4` and `verify/4`, or both calls to `encrypt/4` and `decrypt/4`. For instance, it may be called "user auth" and treated as namespace when generating a token that will be used to authenticate users on channels or on your APIs. The third argument can be any term (string, int, list, etc.) that you wish to codify into the token. Upon valid verification, this same term will be extracted from the token. ### Usage - Phoenix.Token (module) Once a token is signed, we can send it to the client in multiple ways. One is via the meta tag: <%= tag :meta, name: "channel_token", content: Phoenix.Token.sign(@conn, "user auth", @current_user.id) %> Or an endpoint that returns it: def create(conn, params) do user = User.create(params) render(conn, "user.json", %{token: Phoenix.Token.sign(conn, "user auth", user.id), user: user}) end Once the token is sent, the client may now send it back to the server as an authentication mechanism. For example, we can use it to authenticate a user on a Phoenix channel: defmodule MyApp.UserSocket do use Phoenix.Socket def connect(%{"token" => token}, socket, _connect_info) do case Phoenix.Token.verify(socket, "user auth", token, max_age: 86400) do {:ok, user_id} -> socket = assign(socket, :user, Repo.get!(User, user_id)) {:ok, socket} {:error, _} -> :error end end def connect(_params, _socket, _connect_info), do: :error end In this example, the phoenix.js client will send the token in the `connect` command which is then validated by the server. `Phoenix.Token` can also be used for validating APIs, handling password resets, e-mail confirmation and more. ### Phoenix.Token.decrypt/4 (function) Decrypts the original data from the token and verifies its integrity. Its usage is identical to `verify/4` but for encrypted tokens. ### Options - Phoenix.Token.decrypt/4 (function) * `:key_iterations` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 1000 * `:key_length` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 32 * `:key_digest` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to `:sha256` * `:max_age` - verifies the token only if it has been generated "max age" ago in seconds. Defaults to the max age signed in the token by `encrypt/4`. ### Phoenix.Token.encrypt/4 (function) Encodes, encrypts, and signs data into a token you can send to clients. Its usage is identical to that of `sign/4`, but the data is extracted using `decrypt/4`, rather than `verify/4`. ### Options - Phoenix.Token.encrypt/4 (function) * `:key_iterations` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 1000 * `:key_length` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 32 * `:key_digest` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to `:sha256` * `:signed_at` - set the timestamp of the token in seconds. Defaults to `System.os_time(:millisecond)` * `:max_age` - the default maximum age of the token. Defaults to 86400 seconds (1 day) and it may be overridden on `decrypt/4`. ### Phoenix.Token.sign/4 (function) Encodes and signs data into a token you can send to clients. ### Options - Phoenix.Token.sign/4 (function) * `:key_iterations` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 1000 * `:key_length` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 32 * `:key_digest` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to `:sha256` * `:signed_at` - set the timestamp of the token in seconds. Defaults to `System.os_time(:millisecond)` * `:max_age` - the default maximum age of the token. Defaults to 86400 seconds (1 day) and it may be overridden on `verify/4`. ### Phoenix.Token.verify/4 (function) Decodes the original data from the token and verifies its integrity. ### Examples - Phoenix.Token.verify/4 (function) In this scenario we will create a token, sign it, then provide it to a client application. The client will then use this token to authenticate requests for resources from the server. See `Phoenix.Token` summary for more info about creating tokens. iex> user_id = 99 iex> secret = "kjoy3o1zeidquwy1398juxzldjlksahdk3" iex> namespace = "user auth" iex> token = Phoenix.Token.sign(secret, namespace, user_id) The mechanism for passing the token to the client is typically through a cookie, a JSON response body, or HTTP header. For now, assume the client has received a token it can use to validate requests for protected resources. When the server receives a request, it can use `verify/4` to determine if it should provide the requested resources to the client: iex> Phoenix.Token.verify(secret, namespace, token, max_age: 86400) {:ok, 99} In this example, we know the client sent a valid token because `verify/4` returned a tuple of type `{:ok, user_id}`. The server can now proceed with the request. However, if the client had sent an expired token, an invalid token, or `nil`, `verify/4` would have returned an error instead: iex> Phoenix.Token.verify(secret, namespace, expired, max_age: 86400) {:error, :expired} iex> Phoenix.Token.verify(secret, namespace, invalid, max_age: 86400) {:error, :invalid} iex> Phoenix.Token.verify(secret, namespace, nil, max_age: 86400) {:error, :missing} ### Options - Phoenix.Token.verify/4 (function) * `:key_iterations` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 1000 * `:key_length` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to 32 * `:key_digest` - option passed to `Plug.Crypto.KeyGenerator` when generating the encryption and signing keys. Defaults to `:sha256` * `:max_age` - verifies the token only if it has been generated "max age" ago in seconds. Defaults to the max age signed in the token by `sign/4`. ### Phoenix.Token.context/0 (type) ### Phoenix.Token.max_age_opt/0 (type) ### Phoenix.Token.shared_opt/0 (type) ### Phoenix.Token.signed_at_opt/0 (type) ### Phoenix.VerifiedRoutes (module) Provides route generation with compile-time verification. Use of the `sigil_p` macro allows paths and URLs throughout your application to be compile-time verified against your Phoenix router(s). For example, the following path and URL usages: <.link href={~p"/sessions/new"} method="post">Log in redirect(to: url(~p"/posts/#{post}")) Will be verified against your standard `Phoenix.Router` definitions: get "/posts/:post_id", PostController, :show post "/sessions/new", SessionController, :create Unmatched routes will issue compiler warnings: warning: no route path for AppWeb.Router matches "/postz/#{post}" lib/app_web/controllers/post_controller.ex:100: AppWeb.PostController.show/2 Additionally, interpolated ~p values are encoded via the `Phoenix.Param` protocol. For example, a `%Post{}` struct in your application may derive the `Phoenix.Param` protocol to generate slug-based paths rather than ID based ones. This allows you to use `~p"/posts/#{post}"` rather than `~p"/posts/#{post.slug}"` throughout your application. See the `Phoenix.Param` documentation for more details. Query strings are also supported in verified routes, either in traditional query string form: ~p"/posts?page=#{page}" Or as a keyword list or map of values: params = %{page: 1, direction: "asc"} ~p"/posts?#{params}" Like path segments, query strings params are proper URL encoded and may be interpolated directly into the ~p string. ### Options - Phoenix.VerifiedRoutes (module) To verify routes in your application modules, such as controller, templates, and views, `use Phoenix.VerifiedRoutes`, which supports the following options: * `:router` - The required router to verify ~p paths against * `:endpoint` - The optional endpoint for ~p script_name and URL generation * `:statics` - The optional list of static directories to treat as verified paths For example: use Phoenix.VerifiedRoutes, router: AppWeb.Router, endpoint: AppWeb.Endpoint, statics: ~w(images) ### Usage - Phoenix.VerifiedRoutes (module) The majority of path and URL generation needs your application will be met with `~p` and `url/1`, where all information necessary to construct the path or URL is provided by the compile-time information stored in the Endpoint and Router passed to `use Phoenix.VerifiedRoutes`. That said, there are some circumstances where `path/2`, `path/3`, `url/2`, and `url/3` are required: * When the runtime values of the `%Plug.Conn{}`, `%Phoenix.LiveSocket{}`, or a `%URI{}` dictate the formation of the path or URL, which happens under the following scenarios: - `Phoenix.Controller.put_router_url/2` is used to override the endpoint's URL - `Phoenix.Controller.put_static_url/2` is used to override the endpoint's static URL * When the Router module differs from the one passed to `use Phoenix.VerifiedRoutes`, such as library code, or application code that relies on multiple routers. In such cases, the router module can be provided explicitly to `path/3` and `url/3`. ### Tracking Warnings - Phoenix.VerifiedRoutes (module) All static path segments must start with forward slash, and you must have a static segment between dynamic interpolations in order for a route to be verified without warnings. For example, the following path generates proper warnings ~p"/media/posts/#{post}" While this one will not allow the compiler to see the full path: type = "posts" ~p"/media/#{type}/#{post}" In such cases, it's better to write a function such as `media_path/1` which branches on different `~p`'s to handle each type. Like any other compilation warning, the Elixir compiler will warn any time the file that a ~p resides in changes, or if the router is changed. To view previously issued warnings for files that lack new changes, the `--all-warnings` flag may be passed to the `mix compile` task. For the following will show all warnings the compiler has previously encountered when compiling the current application code: $ mix compile --all-warnings *Note: Elixir >= 1.14.0 is required for comprehensive warnings. Older versions will compile properly, but no warnings will be issued. ### Phoenix.VerifiedRoutes.path/2 (macro) Generates the router path with route verification. See `sigil_p/2` for more information. Warns when the provided path does not match against the router specified in `use Phoenix.VerifiedRoutes` or the `@router` module attribute. ### Examples - Phoenix.VerifiedRoutes.path/2 (macro) import Phoenix.VerifiedRoutes redirect(to: path(conn, ~p"/users/top")) redirect(to: path(conn, ~p"/users/#{@user}")) ~H""" <.link href={path(@uri, "/users?page=#{@page}")}>profile <.link href={path(@uri, "/users?#{@params}")}>profile """ ### Phoenix.VerifiedRoutes.path/3 (macro) Generates the router path with route verification. See `sigil_p/2` for more information. Warns when the provided path does not match against the router specified in the router argument. ### Examples - Phoenix.VerifiedRoutes.path/3 (macro) import Phoenix.VerifiedRoutes redirect(to: path(conn, MyAppWeb.Router, ~p"/users/top")) redirect(to: path(conn, MyAppWeb.Router, ~p"/users/#{@user}")) ~H""" <.link href={path(@uri, MyAppWeb.Router, "/users?page=#{@page}")}>profile <.link href={path(@uri, MyAppWeb.Router, "/users?#{@params}")}>profile """ ### Phoenix.VerifiedRoutes.sigil_p/2 (macro) Generates the router path with route verification. Interpolated named parameters are encoded via the `Phoenix.Param` protocol. Warns when the provided path does not match against the router specified in `use Phoenix.VerifiedRoutes` or the `@router` module attribute. ### Examples - Phoenix.VerifiedRoutes.sigil_p/2 (macro) use Phoenix.VerifiedRoutes, endpoint: MyAppWeb.Endpoint, router: MyAppWeb.Router redirect(to: ~p"/users/top") redirect(to: ~p"/users/#{@user}") ~H""" <.link href={~p"/users?page=#{@page}"}>profile <.link href={~p"/users?#{@params}"}>profile """ ### Phoenix.VerifiedRoutes.static_integrity/2 (function) Generates an integrity hash to a static asset given its file path. See `Phoenix.Endpoint.static_integrity/1` for more information. ### Examples - Phoenix.VerifiedRoutes.static_integrity/2 (function) iex> static_integrity(conn, "/assets/app.js") "813dfe33b5c7f8388bccaaa38eec8382" iex> static_integrity(socket, "/assets/app.js") "813dfe33b5c7f8388bccaaa38eec8382" iex> static_integrity(AppWeb.Endpoint, "/assets/app.js") "813dfe33b5c7f8388bccaaa38eec8382" ### Phoenix.VerifiedRoutes.static_path/2 (function) Generates path to a static asset given its file path. See `Phoenix.Endpoint.static_path/1` for more information. ### Examples - Phoenix.VerifiedRoutes.static_path/2 (function) iex> static_path(conn, "/assets/app.js") "/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" iex> static_path(socket, "/assets/app.js") "/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" iex> static_path(AppWeb.Endpoint, "/assets/app.js") "/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" iex> static_path(%URI{path: "/subresource"}, "/assets/app.js") "/subresource/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" ### Phoenix.VerifiedRoutes.static_url/2 (function) Generates url to a static asset given its file path. See `Phoenix.Endpoint.static_url/0` and `Phoenix.Endpoint.static_path/1` for more information. ### Examples - Phoenix.VerifiedRoutes.static_url/2 (function) iex> static_url(conn, "/assets/app.js") "https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" iex> static_url(socket, "/assets/app.js") "https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" iex> static_url(AppWeb.Endpoint, "/assets/app.js") "https://example.com/assets/app-813dfe33b5c7f8388bccaaa38eec8382.js" ### Phoenix.VerifiedRoutes.unverified_path/4 (function) Returns the path with relevant script name prefixes without verification. ### Examples - Phoenix.VerifiedRoutes.unverified_path/4 (function) iex> unverified_path(conn, AppWeb.Router, "/posts") "/posts" iex> unverified_path(conn, AppWeb.Router, "/posts", page: 1) "/posts?page=1" ### Phoenix.VerifiedRoutes.unverified_url/3 (function) Returns the URL for the endpoint from the path without verification. ### Examples - Phoenix.VerifiedRoutes.unverified_url/3 (function) iex> unverified_url(conn, "/posts") "https://example.com/posts" iex> unverified_url(conn, "/posts", page: 1) "https://example.com/posts?page=1" ### Phoenix.VerifiedRoutes.url/1 (macro) Generates the router url with route verification. See `sigil_p/2` for more information. Warns when the provided path does not match against the router specified in `use Phoenix.VerifiedRoutes` or the `@router` module attribute. ### Examples - Phoenix.VerifiedRoutes.url/1 (macro) use Phoenix.VerifiedRoutes, endpoint: MyAppWeb.Endpoint, router: MyAppWeb.Router redirect(to: url(conn, ~p"/users/top")) redirect(to: url(conn, ~p"/users/#{@user}")) ~H""" <.link href={url(@uri, "/users?#{[page: @page]}")}>profile """ The router may also be provided in cases where you want to verify routes for a router other than the one passed to `use Phoenix.VerifiedRoutes`: redirect(to: url(conn, OtherRouter, ~p"/users")) Forwarded routes are also resolved automatically. For example, imagine you have a forward path to an admin router in your main router: defmodule AppWeb.Router do ... forward "/admin", AppWeb.AdminRouter end defmodule AppWeb.AdminRouter do ... get "/users", AppWeb.Admin.UserController end Forwarded paths in your main application router will be verified as usual, such as `~p"/admin/users"`. ### Phoenix.VerifiedRoutes.url/2 (macro) Generates the router url with route verification from the connection, socket, or URI. See `url/1` for more information. ### Phoenix.VerifiedRoutes.url/3 (macro) Generates the url with route verification from the connection, socket, or URI and router. See `url/1` for more information. ### Phoenix.ChannelTest (module) Conveniences for testing Phoenix channels. In channel tests, we interact with channels via process communication, sending and receiving messages. It is also common to subscribe to the same topic the channel subscribes to, allowing us to assert if a given message was broadcast or not. ### Channel testing - Phoenix.ChannelTest (module) To get started, define the module attribute `@endpoint` in your test case pointing to your application endpoint. Then you can directly create a socket and `subscribe_and_join/4` topics and channels: {:ok, _, socket} = socket(UserSocket, "user:id", %{some_assigns: 1}) |> subscribe_and_join(RoomChannel, "room:lobby", %{"id" => 3}) You usually want to set the same ID and assigns your `UserSocket.connect/3` callback would set. Alternatively, you can use the `connect/3` helper to call your `UserSocket.connect/3` callback and initialize the socket with the socket id: {:ok, socket} = connect(UserSocket, %{"some" => "params"}, %{}) {:ok, _, socket} = subscribe_and_join(socket, "room:lobby", %{"id" => 3}) Once called, `subscribe_and_join/4` will subscribe the current test process to the "room:lobby" topic and start a channel in another process. It returns `{:ok, reply, socket}` or `{:error, reply}`. Now, in the same way the channel has a socket representing communication it will push to the client. Our test has a socket representing communication to be pushed to the server. For example, we can use the `push/3` function in the test to push messages to the channel (it will invoke `handle_in/3`): push(socket, "my_event", %{"some" => "data"}) Similarly, we can broadcast messages from the test itself on the topic that both test and channel are subscribed to, triggering `handle_out/3` on the channel: broadcast_from(socket, "my_event", %{"some" => "data"}) > Note only `broadcast_from/3` and `broadcast_from!/3` are available in tests to avoid broadcast messages to be resent to the test process. While the functions above are pushing data to the channel (server) we can use `assert_push/3` to verify the channel pushed a message to the client: assert_push "my_event", %{"some" => "data"} Or even assert something was broadcast into pubsub: assert_broadcast "my_event", %{"some" => "data"} Finally, every time a message is pushed to the channel, a reference is returned. We can use this reference to assert a particular reply was sent from the server: ref = push(socket, "counter", %{}) assert_reply ref, :ok, %{"counter" => 1} ### Checking side-effects - Phoenix.ChannelTest (module) Often one may want to do side-effects inside channels, like writing to the database, and verify those side-effects during their tests. Imagine the following `handle_in/3` inside a channel: def handle_in("publish", %{"id" => id}, socket) do Repo.get!(Post, id) |> Post.publish() |> Repo.update!() {:noreply, socket} end Because the whole communication is asynchronous, the following test would be very brittle: push(socket, "publish", %{"id" => 3}) assert Repo.get_by(Post, id: 3, published: true) The issue is that we have no guarantees the channel has done processing our message after calling `push/3`. The best solution is to assert the channel sent us a reply before doing any other assertion. First change the channel to send replies: def handle_in("publish", %{"id" => id}, socket) do Repo.get!(Post, id) |> Post.publish() |> Repo.update!() {:reply, :ok, socket} end Then expect them in the test: ref = push(socket, "publish", %{"id" => 3}) assert_reply ref, :ok assert Repo.get_by(Post, id: 3, published: true) ### Leave and close - Phoenix.ChannelTest (module) This module also provides functions to simulate leaving and closing a channel. Once you leave or close a channel, because the channel is linked to the test process on join, it will crash the test process: leave(socket) ** (EXIT from #PID<...>) {:shutdown, :leave} You can avoid this by unlinking the channel process in the test: Process.unlink(socket.channel_pid) Notice `leave/1` is async, so it will also return a reference which you can use to check for a reply: ref = leave(socket) assert_reply ref, :ok On the other hand, close is always sync and it will return only after the channel process is guaranteed to have been terminated: :ok = close(socket) This mimics the behaviour existing in clients. To assert that your channel closes or errors asynchronously, you can monitor the channel process with the tools provided by Elixir, and wait for the `:DOWN` message. Imagine an implementation of the `handle_info/2` function that closes the channel when it receives `:some_message`: def handle_info(:some_message, socket) do {:stop, :normal, socket} end In your test, you can assert that the close happened by: Process.monitor(socket.channel_pid) send(socket.channel_pid, :some_message) assert_receive {:DOWN, _, _, _, :normal} ### Phoenix.ChannelTest.assert_broadcast/3 (macro) Asserts the channel has broadcast a message within `timeout`. Before asserting anything was broadcast, we must first subscribe to the topic of the channel in the test process: @endpoint.subscribe("foo:ok") Now we can match on event and payload as patterns: assert_broadcast "some_event", %{"data" => _} In the assertion above, we don't particularly care about the data being sent, as long as something was sent. The timeout is in milliseconds and defaults to the `:assert_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). ### Phoenix.ChannelTest.assert_push/3 (macro) Asserts the channel has pushed a message back to the client with the given event and payload within `timeout`. Notice event and payload are patterns. This means one can write: assert_push "some_event", %{"data" => _} In the assertion above, we don't particularly care about the data being sent, as long as something was sent. The timeout is in milliseconds and defaults to the `:assert_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). **NOTE:** Because event and payload are patterns, they will be matched. This means that if you wish to assert that the received payload is equivalent to an existing variable, you need to pin the variable in the assertion expression. Good: expected_payload = %{foo: "bar"} assert_push "some_event", ^expected_payload Bad: expected_payload = %{foo: "bar"} assert_push "some_event", expected_payload # The code above does not assert the payload matches the described map. ### Phoenix.ChannelTest.assert_reply/4 (macro) Asserts the channel has replied to the given message within `timeout`. Notice status and payload are patterns. This means one can write: ref = push(channel, "some_event") assert_reply ref, :ok, %{"data" => _} In the assertion above, we don't particularly care about the data being sent, as long as something was replied. The timeout is in milliseconds and defaults to the `:assert_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). ### Phoenix.ChannelTest.broadcast_from/3 (function) Broadcast event from pid to all subscribers of the socket topic. The test process will not receive the published message. This triggers the `handle_out/3` callback in the channel. ### Examples - Phoenix.ChannelTest.broadcast_from/3 (function) iex> broadcast_from(socket, "new_message", %{id: 1, content: "hello"}) :ok ### Phoenix.ChannelTest.broadcast_from!/3 (function) Same as `broadcast_from/3`, but raises if broadcast fails. ### Phoenix.ChannelTest.close/2 (function) Emulates the client closing the socket. Closing socket is synchronous and has a default timeout of 5000 milliseconds. ### Phoenix.ChannelTest.connect/3 (macro) Initiates a transport connection for the socket handler. Useful for testing UserSocket authentication. Returns the result of the handler's `connect/3` callback. ### Phoenix.ChannelTest.join/2 (function) See `join/4`. ### Phoenix.ChannelTest.join/3 (function) See `join/4`. ### Phoenix.ChannelTest.join/4 (function) Joins the channel under the given topic and payload. The given channel is joined in a separate process which is linked to the test process. It returns `{:ok, reply, socket}` or `{:error, reply}`. ### Phoenix.ChannelTest.leave/1 (function) Emulates the client leaving the channel. ### Phoenix.ChannelTest.push/3 (function) Pushes a message into the channel. The triggers the `handle_in/3` callback in the channel. ### Examples - Phoenix.ChannelTest.push/3 (function) iex> push(socket, "new_message", %{id: 1, content: "hello"}) reference ### Phoenix.ChannelTest.refute_broadcast/3 (macro) Asserts the channel has not broadcast a message within `timeout`. Like `assert_broadcast`, the event and payload are patterns. The timeout is in milliseconds and defaults to the `:refute_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). Keep in mind this macro will block the test by the timeout value, so use it only when necessary as overuse will certainly slow down your test suite. ### Phoenix.ChannelTest.refute_push/3 (macro) Asserts the channel has not pushed a message to the client matching the given event and payload within `timeout`. Like `assert_push`, the event and payload are patterns. The timeout is in milliseconds and defaults to the `:refute_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). Keep in mind this macro will block the test by the timeout value, so use it only when necessary as overuse will certainly slow down your test suite. ### Phoenix.ChannelTest.refute_reply/4 (macro) Asserts the channel has not replied with a matching payload within `timeout`. Like `assert_reply`, the event and payload are patterns. The timeout is in milliseconds and defaults to the `:refute_receive_timeout` set on the `:ex_unit` application (which defaults to 100ms). Keep in mind this macro will block the test by the timeout value, so use it only when necessary as overuse will certainly slow down your test suite. ### Phoenix.ChannelTest.socket/1 (macro) Builds a socket for the given `socket_module`. The socket is then used to subscribe and join channels. Use this function when you want to create a blank socket to pass to functions like `UserSocket.connect/3`. Otherwise, use `socket/4` if you want to build a socket with existing id and assigns. ### Examples - Phoenix.ChannelTest.socket/1 (macro) socket(MyApp.UserSocket) ### Phoenix.ChannelTest.socket/4 (macro) Builds a socket for the given `socket_module` with given id and assigns. ### Examples - Phoenix.ChannelTest.socket/4 (macro) socket(MyApp.UserSocket, "user_id", %{some: :assign}) If you need to access the socket in another process than the test process, you can give the `pid` of the test process in the 4th argument. ### Examples - Phoenix.ChannelTest.socket/4 (macro) test "connect in a task" do pid = self() task = Task.async(fn -> socket = socket(MyApp.UserSocket, "user_id", %{some: :assign}, test_process: pid) broadcast_from!(socket, "default", %{"foo" => "bar"}) assert_push "default", %{"foo" => "bar"} end) Task.await(task) end ### Phoenix.ChannelTest.subscribe_and_join/2 (function) See `subscribe_and_join/4`. ### Phoenix.ChannelTest.subscribe_and_join/3 (function) See `subscribe_and_join/4`. ### Phoenix.ChannelTest.subscribe_and_join/4 (function) Subscribes to the given topic and joins the channel under the given topic and payload. By subscribing to the topic, we can use `assert_broadcast/3` to verify a message has been sent through the pubsub layer. By joining the channel, we can interact with it directly. The given channel is joined in a separate process which is linked to the test process. If no channel module is provided, the socket's handler is used to lookup the matching channel for the given topic. It returns `{:ok, reply, socket}` or `{:error, reply}`. ### Phoenix.ChannelTest.subscribe_and_join!/2 (function) See `subscribe_and_join!/4`. ### Phoenix.ChannelTest.subscribe_and_join!/3 (function) See `subscribe_and_join!/4`. ### Phoenix.ChannelTest.subscribe_and_join!/4 (function) Same as `subscribe_and_join/4`, but returns either the socket or throws an error. This is helpful when you are not testing joining the channel and just need the socket. ### Phoenix.ConnTest (module) Conveniences for testing Phoenix endpoints and connection related helpers. You likely want to use this module or make it part of your `ExUnit.CaseTemplate`. Once used, this module automatically imports all functions defined here as well as the functions in `Plug.Conn`. ### Endpoint testing - Phoenix.ConnTest (module) `Phoenix.ConnTest` typically works against endpoints. That's the preferred way to test anything that your router dispatches to: @endpoint MyAppWeb.Endpoint test "says welcome on the home page" do conn = get(build_conn(), "/") assert conn.resp_body =~ "Welcome!" end test "logs in" do conn = post(build_conn(), "/login", [username: "john", password: "doe"]) assert conn.resp_body =~ "Logged in!" end The `@endpoint` module attribute contains the endpoint under testing, most commonly your application endpoint itself. If you are using the MyApp.ConnCase generated by Phoenix, it is automatically set for you. As in your router and controllers, the connection is the main abstraction in testing. `build_conn()` returns a new connection and functions in this module can be used to manipulate the connection before dispatching to the endpoint. For example, one could set the accepts header for json requests as follows: build_conn() |> put_req_header("accept", "application/json") |> get("/") You can also create your own helpers, such as `json_conn()` that uses `build_conn/0` and `put_req_header/3`, so you avoid repeating the connection setup throughout your tests. ### Controller testing - Phoenix.ConnTest (module) The functions in this module can also be used for controller testing. While endpoint testing is preferred over controller testing, especially since the controller in Phoenix plays an integration role between your domain and your views, unit testing controllers may be helpful in some situations. For such cases, you need to set the `@endpoint` attribute to your controller and pass an atom representing the action to dispatch: @endpoint MyAppWeb.HomeController test "says welcome on the home page" do conn = get(build_conn(), :index) assert conn.resp_body =~ "Welcome!" end Keep in mind that, once the `@endpoint` variable is set, all tests after setting it will be affected. ### Views testing - Phoenix.ConnTest (module) Under other circumstances, you may be testing a view or another layer that requires a connection for processing. For such cases, a connection can be created using the `build_conn/3` helper: MyApp.UserView.render("hello.html", conn: build_conn(:get, "/")) While `build_conn/0` returns a connection with no request information to it, `build_conn/3` returns a connection with the given request information already filled in. ### Recycling - Phoenix.ConnTest (module) Browsers implement a storage by using cookies. When a cookie is set in the response, the browser stores it and sends it in the next request. To emulate this behaviour, this module provides the idea of recycling. The `recycle/1` function receives a connection and returns a new connection, similar to the one returned by `build_conn/0` with all the response cookies from the previous connection defined as request headers. This is useful when testing multiple routes that require cookies or session to work. Keep in mind Phoenix will automatically recycle the connection between dispatches. This usually works out well most times, but it may discard information if you are modifying the connection before the next dispatch: # No recycling as the connection is fresh conn = get(build_conn(), "/") # The connection is recycled, creating a new one behind the scenes conn = post(conn, "/login") # We can also recycle manually in case we want custom headers conn = conn |> recycle() |> put_req_header("x-special", "nice") # No recycling as we did it explicitly conn = delete(conn, "/logout") Recycling also recycles the "accept" and "authorization" headers, as well as peer data information. ### Phoenix.ConnTest.assert_error_sent/2 (function) Asserts an error was wrapped and sent with the given status. Useful for testing actions that you expect raise an error and have the response wrapped in an HTTP status, with content usually rendered by your MyAppWeb.ErrorHTML view. The function accepts a status either as an integer HTTP status or atom, such as `500` or `:internal_server_error`. The list of allowed atoms is available in `Plug.Conn.Status`. If an error is raised, a 3-tuple of the wrapped response is returned matching the status, headers, and body of the response: {500, [{"content-type", "text/html"} | _], "Internal Server Error"} ### Examples - Phoenix.ConnTest.assert_error_sent/2 (function) assert_error_sent :internal_server_error, fn -> get(build_conn(), "/broken/route") end response = assert_error_sent 500, fn -> get(build_conn(), "/broken/route") end assert {500, [_h | _t], "Internal Server Error"} = response This can also be used to test a route resulted in an error that was translated to a specific response by the `Plug.Status` protocol, such as `Ecto.NoResultsError`: assert_error_sent :not_found, fn -> get(build_conn(), "/something-that-raises-no-results-error") end *Note*: for routes that don't raise an error, but instead return a status, you should test the response directly: conn = get(build_conn(), "/users/not-found") assert response(conn, 404) ### Phoenix.ConnTest.build_conn/0 (function) Creates a connection to be used in upcoming requests. ### Phoenix.ConnTest.build_conn/3 (function) Creates a connection to be used in upcoming requests with a preset method, path and body. This is useful when a specific connection is required for testing a plug or a particular function. ### Phoenix.ConnTest.bypass_through/1 (function) Calls the Endpoint and Router pipelines. Useful for unit testing Plugs where Endpoint and/or router pipeline plugs are required for proper setup. Note the use of `get("/")` following `bypass_through` in the examples below. To execute the plug pipelines, you must issue a request against the router. Most often, you can simply send a GET request against the root path, but you may also specify a different method or path which your pipelines may operate against. ### Examples - Phoenix.ConnTest.bypass_through/1 (function) For example, imagine you are testing an authentication plug in isolation, but you need to invoke the Endpoint plugs and router pipelines to set up session and flash related dependencies. One option is to invoke an existing route that uses the proper pipelines. You can do so by passing the connection and the router name to `bypass_through`: conn = conn |> bypass_through(MyAppWeb.Router) |> get("/some_url") |> MyApp.RequireAuthentication.call([]) assert conn.halted You can also specify which pipelines you want to run: conn = conn |> bypass_through(MyAppWeb.Router, [:browser]) |> get("/") |> MyApp.RequireAuthentication.call([]) assert conn.halted Alternatively, you could only invoke the Endpoint's plugs: conn = conn |> bypass_through() |> get("/") |> MyApp.RequireAuthentication.call([]) assert conn.halted ### Phoenix.ConnTest.bypass_through/2 (function) Calls the Endpoint and Router pipelines for the current route. See `bypass_through/1`. ### Phoenix.ConnTest.bypass_through/3 (function) Calls the Endpoint and the given Router pipelines. See `bypass_through/1`. ### Phoenix.ConnTest.clear_flash/1 (function) Clears up the flash storage. ### Phoenix.ConnTest.connect/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.delete/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.delete_req_cookie/2 (function) Deletes a request cookie. ### Phoenix.ConnTest.dispatch/5 (function) Dispatches the connection to the given endpoint. When invoked via `get/3`, `post/3` and friends, the endpoint is automatically retrieved from the `@endpoint` module attribute, otherwise it must be given as an argument. The connection will be configured with the given `method`, `path_or_action` and `params_or_body`. If `path_or_action` is a string, it is considered to be the request path and stored as so in the connection. If an atom, it is assumed to be an action and the connection is dispatched to the given action. ### Parameters and body - Phoenix.ConnTest.dispatch/5 (function) This function, as well as `get/3`, `post/3` and friends, accepts the request body or parameters as last argument: get(build_conn(), "/", some: "param") get(build_conn(), "/", "some=param&url=encoded") The allowed values are: * `nil` - meaning there is no body * a binary - containing a request body. For such cases, `:headers` must be given as option with a content-type * a map or list - containing the parameters which will automatically set the content-type to multipart. The map or list may contain other lists or maps and all entries will be normalized to string keys * a struct - unlike other maps, a struct will be passed through as-is without normalizing its entries ### Phoenix.ConnTest.ensure_recycled/1 (function) Ensures the connection is recycled if it wasn't already. See `recycle/1` for more information. ### Phoenix.ConnTest.fetch_flash/1 (function) Fetches the flash storage. ### Phoenix.ConnTest.get/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.get_flash/1 (function) Gets the whole flash storage. ### Phoenix.ConnTest.get_flash/2 (function) Gets the given key from the flash storage. ### Phoenix.ConnTest.head/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.html_response/2 (function) Asserts the given status code, that we have an html response and returns the response body if one was set or sent. ### Examples - Phoenix.ConnTest.html_response/2 (function) assert html_response(conn, 200) =~ " " ### Phoenix.ConnTest.init_test_session/2 (function) Inits a session used exclusively for testing. ### Phoenix.ConnTest.json_response/2 (function) Asserts the given status code, that we have a json response and returns the decoded JSON response if one was set or sent. ### Examples - Phoenix.ConnTest.json_response/2 (function) body = json_response(conn, 200) assert "can't be blank" in body["errors"] ### Phoenix.ConnTest.options/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.patch/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.path_params/2 (function) Returns the matched params of the URL for the `%Plug.Conn{}`'s router. Useful for extracting path params out of returned URLs, such as those returned by `Phoenix.LiveViewTest`'s redirected results. ### Examples - Phoenix.ConnTest.path_params/2 (function) assert {:error, {:redirect, %{to: "/posts/123" = to}}} = live(conn, "/path") assert %{id: "123"} = path_params(conn, to) ### Phoenix.ConnTest.post/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.put/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.ConnTest.put_flash/3 (function) Puts the given value under key in the flash storage. ### Phoenix.ConnTest.put_req_cookie/3 (function) Puts a request cookie. ### Phoenix.ConnTest.recycle/2 (function) Recycles the connection. Recycling receives a connection and returns a new connection, containing cookies and relevant information from the given one. This emulates behaviour performed by browsers where cookies returned in the response are available in following requests. By default, only the headers "accept", "accept-language", and "authorization" are recycled. However, a custom set of headers can be specified by passing a list of strings representing its names as the second argument of the function. Note `recycle/1` is automatically invoked when dispatching to the endpoint, unless the connection has already been recycled. ### Phoenix.ConnTest.redirected_params/2 (function) Returns the matched params from the URL the connection was redirected to. Uses the provided `%Plug.Conn{}`s router matched in the previous request. Raises if the response's location header is not set or if the response does not match the redirect status code (defaults to 302). ### Examples - Phoenix.ConnTest.redirected_params/2 (function) assert redirected_to(conn) =~ "/posts/123" assert %{id: "123"} = redirected_params(conn) assert %{id: "123"} = redirected_params(conn, 303) ### Phoenix.ConnTest.redirected_to/2 (function) Returns the location header from the given redirect response. Raises if the response does not match the redirect status code (defaults to 302). ### Examples - Phoenix.ConnTest.redirected_to/2 (function) assert redirected_to(conn) =~ "/foo/bar" assert redirected_to(conn, 301) =~ "/foo/bar" assert redirected_to(conn, :moved_permanently) =~ "/foo/bar" ### Phoenix.ConnTest.response/2 (function) Asserts the given status code and returns the response body if one was set or sent. ### Examples - Phoenix.ConnTest.response/2 (function) conn = get(build_conn(), "/") assert response(conn, 200) =~ "hello world" ### Phoenix.ConnTest.response_content_type/2 (function) Returns the content type as long as it matches the given format. ### Examples - Phoenix.ConnTest.response_content_type/2 (function) # Assert we have an html response with utf-8 charset assert response_content_type(conn, :html) =~ "charset=utf-8" ### Phoenix.ConnTest.text_response/2 (function) Asserts the given status code, that we have a text response and returns the response body if one was set or sent. ### Examples - Phoenix.ConnTest.text_response/2 (function) assert text_response(conn, 200) =~ "hello" ### Phoenix.ConnTest.trace/3 (macro) Dispatches to the current endpoint. See `dispatch/5` for more information. ### Phoenix.CodeReloader (module) A plug and module to handle automatic code reloading. To avoid race conditions, all code reloads are funneled through a sequential call operation. ### Phoenix.CodeReloader.call/2 (function) API used by Plug to invoke the code reloader on every request. ### Phoenix.CodeReloader.init/1 (function) API used by Plug to start the code reloader. ### Phoenix.CodeReloader.reload/2 (function) Reloads code for the current Mix project by invoking the `:reloadable_compilers` on the list of `:reloadable_apps`. This is configured in your application environment like: config :your_app, YourAppWeb.Endpoint, reloadable_compilers: [:gettext, :elixir], reloadable_apps: [:ui, :backend] Keep in mind `:reloadable_compilers` must be a subset of the `:compilers` specified in `project/0` in your `mix.exs`. The `:reloadable_apps` defaults to `nil`. In such case default behaviour is to reload the current project if it consists of a single app, or all applications within an umbrella project. You can set `:reloadable_apps` to a subset of default applications to reload only some of them, an empty list - to effectively disable the code reloader, or include external applications from library dependencies. This function is a no-op and returns `:ok` if Mix is not available. ### Options - Phoenix.CodeReloader.reload/2 (function) * `:reloadable_args` - additional CLI args to pass to the compiler tasks. Defaults to `["--no-all-warnings"]` so only warnings related to the files being compiled are printed ### Phoenix.CodeReloader.reload!/2 (function) Same as `reload/1` but it will raise if Mix is not available. ### Phoenix.CodeReloader.sync/0 (function) Synchronizes with the code server if it is alive. It returns `:ok`. If it is not running, it also returns `:ok`. ### Phoenix.Endpoint.Cowboy2Adapter (module) The Cowboy2 adapter for Phoenix. ### Endpoint configuration - Phoenix.Endpoint.Cowboy2Adapter (module) This adapter uses the following endpoint configuration: * `:http` - the configuration for the HTTP server. It accepts all options as defined by [`Plug.Cowboy`](https://hexdocs.pm/plug_cowboy/). Defaults to `false` * `:https` - the configuration for the HTTPS server. It accepts all options as defined by [`Plug.Cowboy`](https://hexdocs.pm/plug_cowboy/). Defaults to `false` * `:drainer` - a drainer process that triggers when your application is shutting down to wait for any on-going request to finish. It accepts all options as defined by [`Plug.Cowboy.Drainer`](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.Drainer.html). Defaults to `[]`, which will start a drainer process for each configured endpoint, but can be disabled by setting it to `false`. ### Custom dispatch options - Phoenix.Endpoint.Cowboy2Adapter (module) You can provide custom dispatch options in order to use Phoenix's builtin Cowboy server with custom handlers. For example, to handle raw WebSockets [as shown in Cowboy's docs](https://github.com/ninenines/cowboy/tree/master/examples)). The options are passed to both `:http` and `:https` keys in the endpoint configuration. However, once you pass your custom dispatch options, you will need to manually wire the Phoenix endpoint by adding the following rule: {:_, Plug.Cowboy.Handler, {MyAppWeb.Endpoint, []}} For example: config :myapp, MyAppWeb.Endpoint, http: [dispatch: [ {:_, [ {"/foo", MyAppWeb.CustomHandler, []}, {:_, Plug.Cowboy.Handler, {MyAppWeb.Endpoint, []}} ]}]] It is also important to specify your handlers first, otherwise Phoenix will intercept the requests before they get to your handler. ### Phoenix.Endpoint.Cowboy2Adapter.server_info/2 (function) ### Phoenix.Endpoint.SyncCodeReloadPlug (module) Wraps an Endpoint, attempting to sync with Phoenix's code reloader if an exception is raising which indicates that we may be in the middle of a reload. We detect this by looking at the raised exception and seeing if it indicates that the endpoint is not defined. This indicates that the code reloader may be mid way through a compile, and that we should attempt to retry the request after the compile has completed. This is also why this must be implemented in a separate module (one that is not recompiled in a typical code reload cycle), since otherwise it may be the case that the endpoint itself is not defined. ### Phoenix.Endpoint.SyncCodeReloadPlug.call/2 (function) ### Phoenix.Endpoint.SyncCodeReloadPlug.init/1 (function) ### Phoenix.Digester.Compressor (behaviour) Defines the `Phoenix.Digester.Compressor` behaviour for implementing static file compressors. A custom compressor expects 2 functions to be implemented. By default, Phoenix uses only `Phoenix.Digester.Gzip` to compress static files, but additional compressors can be defined and added to the digest process. ### Example - Phoenix.Digester.Compressor (behaviour) If you wanted to compress files using an external brotli compression library, you could define a new module implementing the behaviour and add the module to the list of configured Phoenix static compressors. defmodule MyApp.BrotliCompressor do @behaviour Phoenix.Digester.Compressor def compress_file(file_path, content) do valid_extension = Path.extname(file_path) in Application.fetch_env!(:phoenix, :gzippable_exts) {:ok, compressed_content} = :brotli.encode(content) if valid_extension && byte_size(compressed_content) < byte_size(content) do {:ok, compressed_content} else :error end end def file_extensions do [".br"] end end # config/config.exs config :phoenix, static_compressors: [Phoenix.Digester.Gzip, MyApp.BrotliCompressor], # ... ### Phoenix.Digester.Compressor.compress_file/2 (callback) ### Phoenix.Digester.Compressor.file_extensions/0 (callback) ### Phoenix.Digester.Gzip (module) Gzip compressor for Phoenix.Digester ### Phoenix.Digester.Gzip.compress_file/2 (function) ### Phoenix.Digester.Gzip.file_extensions/0 (function) ### Phoenix.Socket.Broadcast (module) Defines a message sent from pubsub to channels and vice-versa. The message format requires the following keys: * `:topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123" * `:event`- The string event name, for example "phx_join" * `:payload` - The message payload ### Phoenix.Socket.Broadcast.t/0 (type) ### Phoenix.Socket.Message (module) Defines a message dispatched over transport to channels and vice-versa. The message format requires the following keys: * `:topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123" * `:event`- The string event name, for example "phx_join" * `:payload` - The message payload * `:ref` - The unique string ref * `:join_ref` - The unique string ref when joining ### Phoenix.Socket.Message.from_map!/1 (function) Converts a map with string keys into a message struct. Raises `Phoenix.Socket.InvalidMessageError` if not valid. ### Phoenix.Socket.Message.t/0 (type) ### Phoenix.Socket.Reply (module) Defines a reply sent from channels to transports. The message format requires the following keys: * `:topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123" * `:status` - The reply status as an atom * `:payload` - The reply payload * `:ref` - The unique string ref * `:join_ref` - The unique string ref when joining ### Phoenix.Socket.Reply.t/0 (type) ### Phoenix.Socket.Serializer (behaviour) A behaviour that serializes incoming and outgoing socket messages. By default Phoenix provides a serializer that encodes to JSON and decodes JSON messages. Custom serializers may be configured in the socket. ### Phoenix.Socket.Serializer.decode!/2 (callback) Decodes iodata into `Phoenix.Socket.Message` struct. ### Phoenix.Socket.Serializer.encode!/1 (callback) Encodes `Phoenix.Socket.Message` and `Phoenix.Socket.Reply` structs to push format. ### Phoenix.Socket.Serializer.fastlane!/1 (callback) Encodes a `Phoenix.Socket.Broadcast` struct to fastlane format. ### Phoenix.Socket.Transport (behaviour) Outlines the Socket <-> Transport communication. Each transport, such as websockets and longpolling, must interact with a socket. This module defines said behaviour. `Phoenix.Socket` is just one possible implementation of a socket that multiplexes events over multiple channels. If you implement this behaviour, then a transport can directly invoke your implementation, without passing through channels. This module also provides convenience functions for implementing transports. ### Example - Phoenix.Socket.Transport (behaviour) Here is a simple echo socket implementation: defmodule EchoSocket do @behaviour Phoenix.Socket.Transport def child_spec(opts) do # We won't spawn any process, so let's ignore the child spec :ignore end def connect(state) do # Callback to retrieve relevant data from the connection. # The map contains options, params, transport and endpoint keys. {:ok, state} end def init(state) do # Now we are effectively inside the process that maintains the socket. {:ok, state} end def handle_in({text, _opts}, state) do {:reply, :ok, {:text, text}, state} end def handle_info(_, state) do {:ok, state} end def terminate(_reason, _state) do :ok end end It can be mounted in your endpoint like any other socket: socket "/socket", EchoSocket, websocket: true, longpoll: true You can now interact with the socket under `/socket/websocket` and `/socket/longpoll`. ### Custom transports - Phoenix.Socket.Transport (behaviour) Sockets are operated by a transport. When a transport is defined, it usually receives a socket module and the module will be invoked when certain events happen at the transport level. Whenever the transport receives a new connection, it should invoke the `c:connect/1` callback with a map of metadata. Different sockets may require different metadata. If the connection is accepted, the transport can move the connection to another process, if so desires, or keep using the same process. The process responsible for managing the socket should then call `c:init/1`. For each message received from the client, the transport must call `c:handle_in/2` on the socket. For each informational message the transport receives, it should call `c:handle_info/2` on the socket. Transports can optionally implement `c:handle_control/2` for handling control frames such as `:ping` and `:pong`. On termination, `c:terminate/2` must be called. A special atom with reason `:closed` can be used to specify that the client terminated the connection. ### Booting - Phoenix.Socket.Transport (behaviour) Whenever your endpoint starts, it will automatically invoke the `child_spec/1` on each listed socket and start that specification under the endpoint supervisor. Since the socket supervision tree is started by the endpoint, any custom transport must be started after the endpoint in a supervision tree. ### Phoenix.Socket.Transport.check_origin/5 (function) Checks the origin request header against the list of allowed origins. Should be called by transports before connecting when appropriate. If the origin header matches the allowed origins, no origin header was sent or no origin was configured, it will return the given connection. Otherwise a 403 Forbidden response will be sent and the connection halted. It is a noop if the connection has been halted. ### Phoenix.Socket.Transport.check_subprotocols/2 (function) Checks the Websocket subprotocols request header against the allowed subprotocols. Should be called by transports before connecting when appropriate. If the sec-websocket-protocol header matches the allowed subprotocols, it will put sec-websocket-protocol response header and return the given connection. If no sec-websocket-protocol header was sent it will return the given connection. Otherwise a 403 Forbidden response will be sent and the connection halted. It is a noop if the connection has been halted. ### Phoenix.Socket.Transport.child_spec/1 (callback) Returns a child specification for socket management. This is invoked only once per socket regardless of the number of transports and should be responsible for setting up any process structure used exclusively by the socket regardless of transports. Each socket connection is started by the transport and the process that controls the socket likely belongs to the transport. However, some sockets spawn new processes, such as `Phoenix.Socket` which spawns channels, and this gives the ability to start a supervision tree associated to the socket. It receives the socket options from the endpoint, for example: socket "/my_app", MyApp.Socket, shutdown: 5000 means `child_spec([shutdown: 5000])` will be invoked. `:ignore` means no child spec is necessary for this socket. ### Phoenix.Socket.Transport.code_reload/3 (function) Runs the code reloader if enabled. ### Phoenix.Socket.Transport.connect/1 (callback) Connects to the socket. The transport passes a map of metadata and the socket returns `{:ok, state}`, `{:error, reason}` or `:error`. The state must be stored by the transport and returned in all future operations. When `{:error, reason}` is returned, some transports - such as WebSockets - allow customizing the response based on `reason` via a custom `:error_handler`. This function is used for authorization purposes and it may be invoked outside of the process that effectively runs the socket. In the default `Phoenix.Socket` implementation, the metadata expects the following keys: * `:endpoint` - the application endpoint * `:transport` - the transport name * `:params` - the connection parameters * `:options` - a keyword list of transport options, often given by developers when configuring the transport. It must include a `:serializer` field with the list of serializers and their requirements ### Phoenix.Socket.Transport.connect_info/3 (function) Extracts connection information from `conn` and returns a map. Keys are retrieved from the optional transport option `:connect_info`. This functionality is transport specific. Please refer to your transports' documentation for more information. The supported keys are: * `:peer_data` - the result of `Plug.Conn.get_peer_data/1` * `:trace_context_headers` - a list of all trace context headers * `:x_headers` - a list of all request headers that have an "x-" prefix * `:uri` - a `%URI{}` derived from the conn * `:user_agent` - the value of the "user-agent" request header ### Phoenix.Socket.Transport.drainer_spec/1 (callback) Returns a child specification for terminating the socket. This is a process that is started late in the supervision tree with the specific goal of draining connections on application shutdown. Similar to `child_spec/1`, it receives the socket options from the endpoint. ### Phoenix.Socket.Transport.handle_control/2 (callback) Handles incoming control frames. The message is represented as `{payload, options}`. It must return one of: * `{:ok, state}` - continues the socket with no reply * `{:reply, status, reply, state}` - continues the socket with reply * `{:stop, reason, state}` - stops the socket Control frames only supported when using websockets. The `options` contains an `opcode` key, this will be either `:ping` or `:pong`. If a control frame doesn't have a payload, then the payload value will be `nil`. ### Phoenix.Socket.Transport.handle_in/2 (callback) Handles incoming socket messages. The message is represented as `{payload, options}`. It must return one of: * `{:ok, state}` - continues the socket with no reply * `{:reply, status, reply, state}` - continues the socket with reply * `{:stop, reason, state}` - stops the socket The `reply` is a tuple contain an `opcode` atom and a message that can be any term. The built-in websocket transport supports both `:text` and `:binary` opcode and the message must be always iodata. Long polling only supports text opcode. ### Phoenix.Socket.Transport.handle_info/2 (callback) Handles info messages. The message is a term. It must return one of: * `{:ok, state}` - continues the socket with no reply * `{:push, reply, state}` - continues the socket with reply * `{:stop, reason, state}` - stops the socket The `reply` is a tuple contain an `opcode` atom and a message that can be any term. The built-in websocket transport supports both `:text` and `:binary` opcode and the message must be always iodata. Long polling only supports text opcode. ### Phoenix.Socket.Transport.init/1 (callback) Initializes the socket state. This must be executed from the process that will effectively operate the socket. ### Phoenix.Socket.Transport.terminate/2 (callback) Invoked on termination. If `reason` is `:closed`, it means the client closed the socket. This is considered a `:normal` exit signal, so linked process will not automatically exit. See `Process.exit/2` for more details on exit signals. ### Phoenix.Socket.Transport.transport_log/2 (function) Logs the transport request. Available for transports that generate a connection. ### Phoenix.Socket.Transport.state/0 (type) ## Links - [Online documentation](https://hexdocs.pm/phoenix)