{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"never","settings":"","params":[],"results":{"codes":[]}},"next":{"description":"","pages":[]},"title":"Routing","type":"basic","slug":"routing","excerpt":"","body":"Routers are the main hubs of Phoenix applications. They match HTTP requests to controller actions, wire up real-time channel handlers, and define a series of pipeline transformations for scoping middleware to sets of routes.\n\nThe router file that Phoenix generates, `web/router.ex`, will look something like this one.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n\n pipeline :api do\n plug :accepts, [\"json\"]\n end\n\n scope \"/\", HelloPhoenix do\n pipe_through :browser # Use the default browser stack\n\n get \"/\", PageController, :index\n end\n\n # Other scopes may use custom stacks.\n # scope \"/api\", HelloPhoenix do\n # pipe_through :api\n # end\nend\n```\nThe name you gave your application will appear instead of `HelloPhoenix` for both the router module and controller name.\n\nThe first line of this module `use HelloPhoenix.Web, :router` simply makes Phoenix router functions available in our particular router.\n\nScopes have their own section in this guide, so we won't spend time on the `scope \"/\", HelloPhoenix do` block here. The `pipe_through :browser` line will get a full treatment in the Pipeline section of this guide. For now, you only need to know that pipelines allow a set of middleware transformations to be applied to different sets of routes.\n\nInside the scope block, however, we have our first actual route.\n\n```elixir\n get \"/\", PageController, :index\n```\n\n`get` is a Phoenix macro which expands out to define one clause of the `match/3` function. It corresponds to the HTTP verb GET. Similar macros exist for other HTTP verbs including POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE and HEAD.\n\nThe first argument to these macros is the path. Here, it is the root of the application, `/`. The next two arguments are the controller and action we want to have handle this request. These macros may also take other options, which we will see throughout the rest of this guide.\n\nIf this were the only route in our router module, the clause of the `match/3` function would look like this after the macro is expanded.\n\n```elixir\n def match(conn, \"GET\", [\"/\"])\n```\n\nThe body of the match function sets up the connection and invokes the matched controller action.\n\nAs we add more routes, more clauses of the match function will be added to our router module. These will behave like any other multi-clause function in Elixir. They will be tried in order from the top, and the first clause to match the parameters given (verb and path) will be executed. After a match is found, the search will stop and no other clauses will be tried.\n\nThis means that it is possible to create a route which will never match, based on the HTTP verb and the path, regardless of the controller and action.\n\nIf we do create an ambiguous route, the router will still compile, but we will get a warning. Let's see this in action.\n\nDefine this route at the bottom of the `scope \"/\", HelloPhoenix do` block in the router.\n\n```elixir\nget \"/\", RootController, :index\n```\n\nThen run `$ mix compile` at the root of your project. You will see the following warning from the compiler.\n\n```text\nweb/router.ex:1: warning: this clause cannot match because a previous clause at line 1 always matches\nCompiled web/router.ex\n```\n\n### Examining Routes\n\nPhoenix provides a great tool for investigating routes in an application, the mix task `phoenix.routes`.\n\nLet's see how this works. Go to the root of a newly-generated Phoenix application and run `$ mix phoenix.routes`. (If you haven't already done so, you'll need to run `$ mix do deps.get, compile` before running the routes task.) You should see something like the following, generated from the only route we currently have.\n\n```console\n$ mix phoenix.routes\npage_path GET / HelloPhoenix.PageController :index\n```\nThe output tells us that any HTTP GET request for the root of the application will be handled by the `index` action of the `HelloPhoenix.PageController`.\n\n`page_path` is an example of a what Phoenix calls a path helper, and we'll talk about those very soon.\n\n### Resources\n\nThe router supports other macros besides those for HTTP verbs like `get`, `post` and `put`. The most important among them is `resources`, which expands out to eight clauses of the match function.\n\nLet's add a resource to our `web/router.ex` file like this.\n\n```elixir\nscope \"/\", HelloPhoenix do\n pipe_through :browser # Use the default browser stack\n\n get \"/\", PageController, :index\n resources \"/users\", UserController\nend\n```\nFor this purpose, it doesn't matter that we don't actually have a `HelloPhoenix.UserController`.\n\nThen go to the root of your project, and run `$ mix phoenix.routes`\n\nYou should see something like the following. Of course, the name of your project will replace `HelloPhoenix`.\n\n```elixir\nuser_path GET /users HelloPhoenix.UserController :index\nuser_path GET /users/:id/edit HelloPhoenix.UserController :edit\nuser_path GET /users/new HelloPhoenix.UserController :new\nuser_path GET /users/:id HelloPhoenix.UserController :show\nuser_path POST /users HelloPhoenix.UserController :create\nuser_path PATCH /users/:id HelloPhoenix.UserController :update\n PUT /users/:id HelloPhoenix.UserController :update\nuser_path DELETE /users/:id HelloPhoenix.UserController :delete\n```\nThis is the standard matrix of HTTP verbs, paths and controller actions. Let's look at them individually, in a slightly different order.\n\n- A GET request to `/users` will invoke the `index` action to show all the users.\n- A GET request to `/users/:id` will invoke the `show` action with an id to show an individual user identified by that id.\n- A GET request to `/users/new` will invoke the `new` action to present a form for creating a new user.\n- A POST request to `/users` will invoke the `create` action to save a new user to the data store.\n- A GET request to `/users/:id/edit` will invoke the `edit` action with an id to retrieve an individual user from the data store and present the information in a form for editing.\n- A PATCH request to `/users/:id` will invoke the `update` action with an id to save the updated user to the data store.\n- A PUT request to `/users/:id` will also invoke the `update` action with an id to save the updated user to the data store.\n- A DELETE request to `/users/:id` will invoke the `delete` action with an id to remove the individual user from the data store.\n\nIf we don't feel that we need all of these routes, we can be selective using the `:only` and `:except` options.\n\nLet's say we have a read-only posts resource. We could define it like this.\n\n```elixir\nresources \"posts\", PostController, only: [:index, :show]\n```\n\nRunning `$ mix phoenix.routes` shows that we now only have the routes to the index and show actions defined.\n\n```elixir\npost_path GET /posts HelloPhoenix.PostController :index\npost_path GET /posts/:id HelloPhoenix.PostController :show\n```\n\nSimilarly, if we have a comments resource, and we don't want to provide a route to delete one, we could define a route like this.\n\n```elixir\nresources \"comments\", CommentController, except: [:delete]\n```\n\nRunning `$ mix phoenix.routes` now shows that we have all the routes except the DELETE request to the delete action.\n\n```elixir\ncomment_path GET /comments HelloPhoenix.CommentController :index\ncomment_path GET /comments/:id/edit HelloPhoenix.CommentController :edit\ncomment_path GET /comments/new HelloPhoenix.CommentController :new\ncomment_path GET /comments/:id HelloPhoenix.CommentController :show\ncomment_path POST /comments HelloPhoenix.CommentController :create\ncomment_path PATCH /comments/:id HelloPhoenix.CommentController :update\n PUT /comments/:id HelloPhoenix.CommentController :update\n```\n### Path Helpers\n\nPath helpers are functions which are dynamically defined on the `Router.Helpers` module for an individual application. For us, that is `HelloPhoenix.Router.Helpers`. Their names are derived from the name of the controller used in the route definition. Our controller is `HelloPhoenix.PageController`, and `page_path` is the function which will return the path to the root of our application.\n\nThat's a mouthful. Let's see it in action. Run `$ iex -S mix` at the root of the project. When we call the `page_path` function on our router helpers with the `Endpoint` or connection and action as arguments, it returns the path to us.\n\n```elixir\niex> HelloPhoenix.Router.Helpers.page_path(HelloPhoenix.Endpoint, :index)\n\"/\"\n```\n\nThis is significant because we can use the `page_path` function in a template to link to the root of our application. Note: If that function invocation seems uncomfortably long, there is a solution. By including `import HelloPhoenix.Router.Helpers` in our main application view.\n\n```html\n<a href=\"<%= page_path(:::at:::conn, :index) %>\">To the Welcome Page!</a>\n```\nPlease see the [View Guide](http://www.phoenixframework.org/docs/views) for more information.\n\nThis pays off tremendously if we should ever have to change the path of our route in the router. Since the path helpers are built dynamically from the routes, any calls to `page_path` in our templates will still work.\n\n### More on Path Helpers\n\nWhen we ran the `phoenix.routes` task for our user resource, it listed the `user_path` as the path helper function for each line of output. Here is what that translates to for each action.\n\n```elixir\niex> import HelloPhoenix.Router.Helpers\niex> alias HelloPhoenix.Endpoint\niex> user_path(Endpoint, :index)\n\"/users\"\n\niex> user_path(Endpoint, :show, 17)\n\"/users/17\"\n\niex> user_path(Endpoint, :new)\n\"/users/new\"\n\niex> user_path(Endpoint, :create)\n\"/users\"\n\niex> user_path(Endpoint, :edit, 37)\n\"/users/37/edit\"\n\niex> user_path(Endpoint, :update, 37)\n\"/users/37\"\n\niex> user_path(Endpoint, :delete, 17)\n\"/users/17\"\n```\n\nWhat about paths with query strings? Phoenix has you covered. By adding an optional fourth argument of key value pairs, the path helpers will return those pairs in the query string.\n\n```elixir\niex> user_path(Endpoint, :show, 17, admin: true, active: false)\n\"/users/17?admin=true&active=false\"\n```\n\nWhat if we need a full url instead of a path? Just replace `_path` by `_url`:\n\n```elixir\niex(3)> user_url(Endpoint, :index)\n\"http://localhost:4000/users\"\n```\nApplication endpoints will have their own guide soon. For now, think of them as the entity that handles requests just up to the point where the router takes over. That includes starting the app/server, applying configuration, and applying the plugs common to all requests.\n\nThe `_url` functions will get the host, port, proxy port and ssl information needed to construct the full url from the configuration parameters set for each environment. We'll talk about configuration in more detail in its own guide. For now, you can take a look at `/config/dev.exs` file in your own project to see what those values are.\n\n### Nested Resources\n\nIt is also possible to nest resources in a Phoenix router. Let's say we also have a posts resource which has a one to many relationship with users. That is to say, a user can create many posts, and an individual post belongs to only one user. We can represent that by adding a nested route in `web/router.ex` like this.\n\n```elixir\nresources \"users\", UserController do\n resources \"posts\", PostController\nend\n```\nWhen we run `$ mix phoenix.routes` now, in addition to the routes we saw for users above, we get the following set of routes:\n\n```elixir\n. . .\nuser_post_path GET users/:user_id/posts HelloPhoenix.PostController :index\nuser_post_path GET users/:user_id/posts/:id/edit HelloPhoenix.PostController :edit\nuser_post_path GET users/:user_id/posts/new HelloPhoenix.PostController :new\nuser_post_path GET users/:user_id/posts/:id HelloPhoenix.PostController :show\nuser_post_path POST users/:user_id/posts HelloPhoenix.PostController :create\nuser_post_path PATCH users/:user_id/posts/:id HelloPhoenix.PostController :update\n PUT users/:user_id/posts/:id HelloPhoenix.PostController :update\nuser_post_path DELETE users/:user_id/posts/:id HelloPhoenix.PostController :delete\n```\n\nWe see that each of these routes scopes the posts to a user id. For the first one, we will invoke the `PostController` `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.\n\nWhen calling path helper functions for nested routes, we will need to pass the ids in the order they came in the route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`. Let's remember to alias our `HelloPhoenix.Endpoint` before we begin.\n\n```elixir\niex> alias HelloPhoenix.Endpoint\niex> HelloPhoenix.Router.Helpers.user_post_path(Endpoint, :show, 42, 17)\n\"/users/42/posts/17\"\n```\n\nAgain, if we add a key value pair to the end of the function call, it is added to the query string.\n\n```elixir\niex> HelloPhoenix.Router.Helpers.user_post_path(Endpoint, :index, 42, active: true)\n\"/users/42/posts?active=true\"\n```\n\n### Scoped Routes\n\nScopes are a way to group routes under a common path prefix and scoped set of plug middleware. We might want to do this for admin functionality, APIs and especially for versioned APIs. Let's say we have user generated reviews on a site, and that those reviews first need to be approved by an admin. The semantics of these resources are quite different, and they may not share the same controller, so we want to keep them separate.\n\nThe paths to the user facing reviews would look like a standard resource.\n\n```text\n/reviews\n/reviews/1234\n/reviews/1234/edit\n\nand so on\n```\n\nThe admin review paths could be prefixed with `/admin`.\n\n```text\n/admin/reviews\n/admin/reviews/1234\n/admin/reviews/1234/edit\n\nand so on\n```\n\nWe accomplish this with a scoped route that sets a path option to `/admin` like this one. For now, let's not nest this scope inside of any other scopes (like the `scope \"/\", HelloPhoenix do` one provided for us in a new app).\n\n```elixir\nscope \"/admin\" do\n pipe_through :browser\n\n resources \"/reviews\", HelloPhoenix.Admin.ReviewController\nend\n```\n\nNote that Phoenix will assume that the path we set ought to begin with a slash, so `scope \"/admin\" do` and `scope \"admin\" do` will both produce the same results.\n\nNote also, that the way this scope is currently defined, we need to fully qualify our controller name, `HelloPhoenix.Admin.ReviewController`. We'll fix that in a minute.\n\nRunning `$ mix phoenix.routes` again, in addition to the previous set of routes we get the following:\n\n```elixir\n. . .\nreview_path GET /admin/reviews HelloPhoenix.Admin.ReviewController :index\nreview_path GET /admin/reviews/:id/edit HelloPhoenix.Admin.ReviewController :edit\nreview_path GET /admin/reviews/new HelloPhoenix.Admin.ReviewController :new\nreview_path GET /admin/reviews/:id HelloPhoenix.Admin.ReviewController :show\nreview_path POST /admin/reviews HelloPhoenix.Admin.ReviewController :create\nreview_path PATCH /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\n PUT /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\nreview_path DELETE /admin/reviews/:id HelloPhoenix.Admin.ReviewController :delete\n```\n\nThis looks good, but there is a problem here. Remember that we wanted both user facing reviews routes `/reviews` as well as the admin ones `/admin/reviews`. If we now include the user facing reviews in our router like this:\n\n```elixir\nscope \"/\", HelloPhoenix do\n pipe_through :browser\n . . .\n resources \"/reviews\", ReviewController\n . . .\nend\n\nscope \"/admin\" do\n resources \"/reviews\", HelloPhoenix.Admin.ReviewController\nend\n```\n\nand we run `$ mix phoenix.routes`, we get this output:\n\n```elixir\n. . .\nreview_path GET /reviews HelloPhoenix.ReviewController :index\nreview_path GET /reviews/:id/edit HelloPhoenix.ReviewController :edit\nreview_path GET /reviews/new HelloPhoenix.ReviewController :new\nreview_path GET /reviews/:id HelloPhoenix.ReviewController :show\nreview_path POST /reviews HelloPhoenix.ReviewController :create\nreview_path PATCH /reviews/:id HelloPhoenix.ReviewController :update\n PUT /reviews/:id HelloPhoenix.ReviewController :update\nreview_path DELETE /reviews/:id HelloPhoenix.ReviewController :delete\n. . .\nreview_path GET /admin/reviews HelloPhoenix.Admin.ReviewController :index\nreview_path GET /admin/reviews/:id/edit HelloPhoenix.Admin.ReviewController :edit\nreview_path GET /admin/reviews/new HelloPhoenix.Admin.ReviewController :new\nreview_path GET /admin/reviews/:id HelloPhoenix.Admin.ReviewController :show\nreview_path POST /admin/reviews HelloPhoenix.Admin.ReviewController :create\nreview_path PATCH /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\n PUT /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\nreview_path DELETE /admin/reviews/:id HelloPhoenix.Admin.ReviewController :delete\n```\n\nThe actual routes we get all look right, except for the path helper `review_path` at the beginning of each line. We are getting the same helper for both the user facing review routes and the admin ones, which is not correct. We can fix this problem by adding an `as: :admin` option to our admin scope.\n\n```elixir\nscope \"/\", HelloPhoenix do\n pipe_through :browser\n . . .\n resources \"/reviews\", ReviewController\n . . .\nend\n\nscope \"/admin\", as: :admin do\n resources \"/reviews\", HelloPhoenix.Admin.ReviewController\nend\n```\n\n`$ mix phoenix.routes` now shows us we have what we are looking for.\n\n```elixir\n. . .\n review_path GET /reviews HelloPhoenix.ReviewController :index\n review_path GET /reviews/:id/edit HelloPhoenix.ReviewController :edit\n review_path GET /reviews/new HelloPhoenix.ReviewController :new\n review_path GET /reviews/:id HelloPhoenix.ReviewController :show\n review_path POST /reviews HelloPhoenix.ReviewController :create\n review_path PATCH /reviews/:id HelloPhoenix.ReviewController :update\n PUT /reviews/:id HelloPhoenix.ReviewController :update\n review_path DELETE /reviews/:id HelloPhoenix.ReviewController :delete\n. . .\nadmin_review_path GET /admin/reviews HelloPhoenix.Admin.ReviewController :index\nadmin_review_path GET /admin/reviews/:id/edit HelloPhoenix.Admin.ReviewController :edit\nadmin_review_path GET /admin/reviews/new HelloPhoenix.Admin.ReviewController :new\nadmin_review_path GET /admin/reviews/:id HelloPhoenix.Admin.ReviewController :show\nadmin_review_path POST /admin/reviews HelloPhoenix.Admin.ReviewController :create\nadmin_review_path PATCH /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\n PUT /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\nadmin_review_path DELETE /admin/reviews/:id HelloPhoenix.Admin.ReviewController :delete\n```\n\nThe path helpers now return what we want them to as well. Run `$ iex -S mix` and give it a try yourself.\n\n```elixir\niex(1)> HelloPhoenix.Router.Helpers.review_path(Endpoint, :index)\n\"/reviews\"\n\niex(2)> HelloPhoenix.Router.Helpers.admin_review_path(Endpoint, :show, 1234)\n\"/admin/reviews/1234\"\n```\n\nWhat if we had a number of resources that were all handled by admins? We could put all of them inside the same scope like this:\n\n```elixir\nscope \"/admin\", as: :admin do\n pipe_through :browser\n\n resources \"/images\", HelloPhoenix.Admin.ImageController\n resources \"/reviews\", HelloPhoenix.Admin.ReviewController\n resources \"/users\", HelloPhoenix.Admin.UserController\nend\n```\n\nHere's what `$ mix phoenix.routes` tells us:\n\n```elixir\n. . .\n admin_image_path GET /admin/images HelloPhoenix.Admin.ImageController :index\n admin_image_path GET /admin/images/:id/edit HelloPhoenix.Admin.ImageController :edit\n admin_image_path GET /admin/images/new HelloPhoenix.Admin.ImageController :new\n admin_image_path GET /admin/images/:id HelloPhoenix.Admin.ImageController :show\n admin_image_path POST /admin/images HelloPhoenix.Admin.ImageController :create\n admin_image_path PATCH /admin/images/:id HelloPhoenix.Admin.ImageController :update\n PUT /admin/images/:id HelloPhoenix.Admin.ImageController :update\n admin_image_path DELETE /admin/images/:id HelloPhoenix.Admin.ImageController :delete\nadmin_review_path GET /admin/reviews HelloPhoenix.Admin.ReviewController :index\nadmin_review_path GET /admin/reviews/:id/edit HelloPhoenix.Admin.ReviewController :edit\nadmin_review_path GET /admin/reviews/new HelloPhoenix.Admin.ReviewController :new\nadmin_review_path GET /admin/reviews/:id HelloPhoenix.Admin.ReviewController :show\nadmin_review_path POST /admin/reviews HelloPhoenix.Admin.ReviewController :create\nadmin_review_path PATCH /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\n PUT /admin/reviews/:id HelloPhoenix.Admin.ReviewController :update\nadmin_review_path DELETE /admin/reviews/:id HelloPhoenix.Admin.ReviewController :delete\n admin_user_path GET /admin/users HelloPhoenix.Admin.UserController :index\n admin_user_path GET /admin/users/:id/edit HelloPhoenix.Admin.UserController :edit\n admin_user_path GET /admin/users/new HelloPhoenix.Admin.UserController :new\n admin_user_path GET /admin/users/:id HelloPhoenix.Admin.UserController :show\n admin_user_path POST /admin/users HelloPhoenix.Admin.UserController :create\n admin_user_path PATCH /admin/users/:id HelloPhoenix.Admin.UserController :update\n PUT /admin/users/:id HelloPhoenix.Admin.UserController :update\n admin_user_path DELETE /admin/users/:id HelloPhoenix.Admin.UserController :delete\n```\n\nThis is great, exactly what we want, but we can make it even better. Notice that for each resource, we needed to fully qualify the controller name by prefixing it with `HelloPhoenix.Admin`. That's tedious and error prone. Assuming that the name of each controller begins with `HelloPhoenix.Admin`, then we can add a `HelloPhoenix.Admin` option to our scope declaration just after the scope path, and all of our routes will have the correct, fully qualified controller name.\n\n```elixir\nscope \"/admin\", HelloPhoenix.Admin, as: :admin do\n pipe_through :browser\n\n resources \"/images\", ImageController\n resources \"/reviews\", ReviewController\n resources \"/users\", UserController\nend\n```\n\nNow run `$ mix phoenix.routes` again and you can see that we get the same result as above when we qualified each controller name individually.\n\nAs an extra bonus, we could nest all of the routes for our application inside a scope that simply has an alias for the name of our Phoenix app, and eliminate the duplication in our controller names.\n\nPhoenix already does this now for us in the generated router for a new application (see beginning of this section). Notice here the use of `HelloPhoenix.Router` in the `defmodule` declaration:\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n scope \"/\", HelloPhoenix do\n pipe_through :browser\n\n get \"/images\", ImageController, :index\n resources \"/reviews\", ReviewController\n resources \"/users\", UserController\n end\nend\n```\n\nAgain `$ mix phoenix.routes` tells us that all of our controllers now have the correct, fully-qualified names.\n\n```elixir\nimage_path GET /images HelloPhoenix.ImageController :index\nreview_path GET /reviews HelloPhoenix.ReviewController :index\nreview_path GET /reviews/:id/edit HelloPhoenix.ReviewController :edit\nreview_path GET /reviews/new HelloPhoenix.ReviewController :new\nreview_path GET /reviews/:id HelloPhoenix.ReviewController :show\nreview_path POST /reviews HelloPhoenix.ReviewController :create\nreview_path PATCH /reviews/:id HelloPhoenix.ReviewController :update\n PUT /reviews/:id HelloPhoenix.ReviewController :update\nreview_path DELETE /reviews/:id HelloPhoenix.ReviewController :delete\n user_path GET /users HelloPhoenix.UserController :index\n user_path GET /users/:id/edit HelloPhoenix.UserController :edit\n user_path GET /users/new HelloPhoenix.UserController :new\n user_path GET /users/:id HelloPhoenix.UserController :show\n user_path POST /users HelloPhoenix.UserController :create\n user_path PATCH /users/:id HelloPhoenix.UserController :update\n PUT /users/:id HelloPhoenix.UserController :update\n user_path DELETE /users/:id HelloPhoenix.UserController :delete\n```\n\nScopes can also be nested, just like resources. Suppose that we had a versioned API with resources defined for images, reviews and users. We could then setup routes for the versioned API like this:\n\n```elixir\nscope \"/api\", HelloPhoenix.Api, as: :api do\n pipe_through :api\n\n scope \"/v1\", V1, as: :v1 do\n resources \"/images\", ImageController\n resources \"/reviews\", ReviewController\n resources \"/users\", UserController\n end\nend\n```\n\n`$ mix phoenix.routes` tells us that we have the routes we're looking for.\n\n```elixir\n api_v1_image_path GET /api/v1/images HelloPhoenix.Api.V1.ImageController :index\n api_v1_image_path GET /api/v1/images/:id/edit HelloPhoenix.Api.V1.ImageController :edit\n api_v1_image_path GET /api/v1/images/new HelloPhoenix.Api.V1.ImageController :new\n api_v1_image_path GET /api/v1/images/:id HelloPhoenix.Api.V1.ImageController :show\n api_v1_image_path POST /api/v1/images HelloPhoenix.Api.V1.ImageController :create\n api_v1_image_path PATCH /api/v1/images/:id HelloPhoenix.Api.V1.ImageController :update\n PUT /api/v1/images/:id HelloPhoenix.Api.V1.ImageController :update\n api_v1_image_path DELETE /api/v1/images/:id HelloPhoenix.Api.V1.ImageController :delete\napi_v1_review_path GET /api/v1/reviews HelloPhoenix.Api.V1.ReviewController :index\napi_v1_review_path GET /api/v1/reviews/:id/edit HelloPhoenix.Api.V1.ReviewController :edit\napi_v1_review_path GET /api/v1/reviews/new HelloPhoenix.Api.V1.ReviewController :new\napi_v1_review_path GET /api/v1/reviews/:id HelloPhoenix.Api.V1.ReviewController :show\napi_v1_review_path POST /api/v1/reviews HelloPhoenix.Api.V1.ReviewController :create\napi_v1_review_path PATCH /api/v1/reviews/:id HelloPhoenix.Api.V1.ReviewController :update\n PUT /api/v1/reviews/:id HelloPhoenix.Api.V1.ReviewController :update\napi_v1_review_path DELETE /api/v1/reviews/:id HelloPhoenix.Api.V1.ReviewController :delete\n api_v1_user_path GET /api/v1/users HelloPhoenix.Api.V1.UserController :index\n api_v1_user_path GET /api/v1/users/:id/edit HelloPhoenix.Api.V1.UserController :edit\n api_v1_user_path GET /api/v1/users/new HelloPhoenix.Api.V1.UserController :new\n api_v1_user_path GET /api/v1/users/:id HelloPhoenix.Api.V1.UserController :show\n api_v1_user_path POST /api/v1/users HelloPhoenix.Api.V1.UserController :create\n api_v1_user_path PATCH /api/v1/users/:id HelloPhoenix.Api.V1.UserController :update\n PUT /api/v1/users/:id HelloPhoenix.Api.V1.UserController :update\n api_v1_user_path DELETE /api/v1/users/:id HelloPhoenix.Api.V1.UserController :delete\n```\nInterestingly, we can use multiple scopes with the same path as long as we are careful not to duplicate routes. If we do duplicate a route, we'll get this familiar warning.\n\n```console\nwarning: this clause cannot match because a previous clause at line 16 always matches\n```\nThis router is perfectly fine with two scopes defined for the same path.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use Phoenix.Router\n . . .\n scope \"/\", HelloPhoenix do\n pipe_through :browser\n\n resources \"users\", UserController\n end\n\n scope \"/\", AnotherApp do\n pipe_through :browser\n\n resources \"posts\", PostController\n end\n . . .\nend\n```\nAnd when we run `$ mix phoenix.routes`, we see the following output.\n\n```elixir\nuser_path GET /users HelloPhoenix.UserController :index\nuser_path GET /users/:id/edit HelloPhoenix.UserController :edit\nuser_path GET /users/new HelloPhoenix.UserController :new\nuser_path GET /users/:id HelloPhoenix.UserController :show\nuser_path POST /users HelloPhoenix.UserController :create\nuser_path PATCH /users/:id HelloPhoenix.UserController :update\n PUT /users/:id HelloPhoenix.UserController :update\nuser_path DELETE /users/:id HelloPhoenix.UserController :delete\npost_path GET /posts AnotherApp.PostController :index\npost_path GET /posts/:id/edit AnotherApp.PostController :edit\npost_path GET /posts/new AnotherApp.PostController :new\npost_path GET /posts/:id AnotherApp.PostController :show\npost_path POST /posts AnotherApp.PostController :create\npost_path PATCH /posts/:id AnotherApp.PostController :update\n PUT /posts/:id AnotherApp.PostController :update\npost_path DELETE /posts/:id AnotherApp.PostController :delete\n```\n\n### Pipelines\n\nWe have come quite a long way in this guide without talking about one of the first lines we saw in the router - `pipe_through :browser`. It's time to fix that.\n\nRemember in the [Overview Guide](http://www.phoenixframework.org/docs/overview) when we described plugs as being stacked and executable in a pre-determined order, like a pipeline? Now we're going to take a closer look at how these plug stacks work in the router.\n\nPipelines are simply plugs stacked up together in a specific order and given a name. They allow us to customize behaviors and transformations related to the handling of requests. Phoenix provides us with some default pipelines for a number of common tasks. In turn we can customize them as well as create new pipelines to meet our needs.\n\nA newly generated Phoenix application defines two pipelines called `:browser` and `:api`. We'll get to those in a minute, but first we need to talk about the plug stack in the Endpoint plugs.\n\n##### The Endpoint Plugs\n\nEndpoints organize all the plugs common to every request, and apply them before dispatching into the router(s) with their underlying `:browser`, `:api`, and custom pipelines. The default Endpoint plugs do quite a lot of work. Here they are in order.\n\n- [Plug.Static](http://hexdocs.pm/plug/Plug.Static.html) - serves static assets. Since this plug comes before the logger, serving of static assets is not logged\n\n- [Plug.Logger](http://hexdocs.pm/plug/Plug.Logger.html) - logs incoming requests\n\n- [Phoenix.CodeReloader](http://hexdocs.pm/phoenix/Phoenix.CodeReloader.html) - a plug that enables code reloading for all entries in the web directory. It is configured directly in the Phoenix application\n\n- [Plug.Parsers](http://hexdocs.pm/plug/Plug.Parsers.html) - parses the request body when a known parser is available. By default parsers urlencoded, multipart and json (with poison). The request body is left untouched when the request content-type cannot be parsed\n\n- [Plug.MethodOverride](http://hexdocs.pm/plug/Plug.MethodOverride.html) - converts the request method to\n PUT, PATCH or DELETE for POST requests with a valid `_method` parameter\n\n- [Plug.Head](http://hexdocs.pm/plug/Plug.Head.html) - converts HEAD requests to GET requests and strips the response body\n\n- [Plug.Session](http://hexdocs.pm/plug/Plug.Session.html) - a plug that sets up session management.\n Note that `fetch_session/2` must still be explicitly called before using the session as this plug just sets up how the session is fetched\n\n- [Plug.Router](http://hexdocs.pm/plug/Plug.Router.html) - plugs a router into the request cycle\n\n##### The `:browser` and `:api` Pipelines\n\nPhoenix defines two other pipelines by default, `:browser` and `:api`. The router will invoke these after it matches a route, assuming we have called `pipe_through/1` with them in the enclosing scope.\n\nAs their names suggest, the `:browser` pipeline prepares for routes which render requests for a browser. The `:api` pipeline prepares for routes which produce data for an api.\n\nThe `:browser` pipeline has four plugs: `plug :accepts, [\"html\"]` which defines the request format or formats which will be accepted, `:fetch_session`, which, naturally, fetches the session data and makes it available in the connection, `:fetch_flash` which retrieves any flash messages which may have been set, and `:protect_from_forgery`, which protects form posts from cross site forgery.\n\nCurrently, the `:api` pipeline only defines `plug :accepts, [\"json\"]`.\n\nThe router invokes a pipeline on a route defined within a scope. If no scope is defined, the router will invoke the pipeline on all the routes in the router. If we call `pipe_through/1` from within a nested scope, the router will invoke it on the inner scope only.\n\nThose are a lot of words bunched up together. Let's take a look at some examples to untangle their meaning.\n\nHere's another look at the router from a newly generated Phoenix application, this time with the api scope uncommented back in and a route added.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n\n pipeline :api do\n plug :accepts, [\"json\"]\n end\n\n scope \"/\", HelloPhoenix do\n pipe_through :browser\n\n get \"/\", PageController, :index\n end\n\n # Other scopes may use custom stacks.\n scope \"/api\", HelloPhoenix do\n pipe_through :api\n\n resources \"reviews\", ReviewController\n end\nend\n```\n\nWhen the server accepts a request, the request will always first pass through the plugs in our Endpoint, after which it will attempt to match on the path and HTTP verb.\n\nLet's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to the `PageController` `index` action.\n\nConversely, if the request matches any of the routes defined by the `resources/2` macro, the router will pipe it through the `:api` pipeline - which currently does nothing - before it dispatches further to the correct action of the `HelloPhoenix.ReviewController`.\n\nIf we know that our application only renders views for the browser, we can simplify our router quite a bit by removing the `api` stuff as well as the scopes:\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n\n pipe_through :browser\n\n get \"/\", HelloPhoenix.PageController, :index\n\n resources \"reviews\", HelloPhoenix.ReviewController\nend\n```\nRemoving all scopes forces the router to invoke the `:browser` pipeline on all routes.\n\nLet's stretch these ideas out a little bit more. What if we need to pipe requests through both `:browser` and one or more custom pipelines? We simply `pipe_through` a list of pipelines, and Phoenix will invoke them in order.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n ...\n\n scope \"/reviews\" do\n # Use the default browser stack.\n pipe_through [:browser, :review_checks, :other_great_stuff]\n\n resources \"reviews\", HelloPhoenix.ReviewController\n end\nend\n```\n\nHere's another example where nested scopes have different pipelines:\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n ...\n\n scope \"/\", HelloPhoenix do\n pipe_through :browser\n\n resources \"posts\", PostController\n\n scope \"/reviews\" do\n pipe_through :review_checks\n\n resources \"reviews\", ReviewController\n end\n end\nend\n```\n\nIn general, the scoping rules for pipelines behave as you might expect. In this example, all routes will pipe through the `:browser` pipeline, because the `/` scope encloses all the routes. Only the `reviews` resources routes will pipe through the `:review_checks` pipeline, however, because we declare `pipe_through :review_checks` within the `/reviews` scope, where the `reviews` resources routes are.\n\n##### Creating New Pipelines\n\nPhoenix allows us to create our own custom pipelines anywhere in the router. It couldn't be simpler. We just call the `pipeline/2` macro with an atom for the name of our new pipeline and a block with all the plugs we want in it.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n pipeline :browser do\n plug :accepts, [\"html\"]\n plug :fetch_session\n plug :fetch_flash\n plug :protect_from_forgery\n end\n\n pipeline :review_checks do\n plug :ensure_authenticated_user\n plug :ensure_user_owns_review\n end\n\n scope \"/reviews\", HelloPhoenix do\n pipe_through :review_checks\n\n resources \"reviews\", ReviewController\n end\nend\n```\n\n### Channel Routes\n\nChannels are a very exciting, real-time component of the Phoenix framework. Channels handle incoming and outgoing messages broadcast over a socket for a given topic. Channel routes, then, need to match requests by socket and topic in order to dispatch to the correct channel. (For a more detailed description of channels and their behavior, please see the [Channel Guide](http://www.phoenixframework.org/docs/channels).)\n\nWe define sockets in the router with a block, a path to the socket's mount point, and (optionally) the name of our application to fully qualify our channel module name. This should look familiar after seeing our scope definitions above.\n\nHere's what that looks like in our router file:\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n socket \"/ws\", HelloPhoenix do\n end\n ...\nend\n```\n\nNext, we need to use the `channel/3` macro to match a topic to the channel which will handle its requests. If we have a channel module called `RoomChannel` and a topic called `\"rooms:*\"`, the code to do this is straightforward.\n\n```elixir\ndefmodule HelloPhoenix.Router do\n use HelloPhoenix.Web, :router\n\n socket \"/ws\", HelloPhoenix do\n channel \"rooms:*\", RoomChannel\n end\n . . .\nend\n```\n\nTopics are just string identifiers. The form we are using here is a convention which allows us to define topics and subtopics in the same string - \"topic:subtopic\". The `*` is a wildcard character which allows us to match on any subtopic, so `\"rooms:lobby\"` and `\"rooms:kitchen\"` would both match this route.\n\nNow that we have a channel route defined, let's see what `$ mix phoenix.routes` shows us.\n\n```console\n$ mix phoenix.routes\n. . .\nweb_socket_path GET /ws Phoenix.Transports.WebSocket.upgrade/2\nweb_socket_path POST /ws Phoenix.Transports.WebSocket.upgrade/2\nlong_poller_path GET /ws/poll Phoenix.Transports.LongPoller.poll/2\nlong_poller_path POST /ws/poll Phoenix.Transports.LongPoller.publish/2\n```\n\nNotice that our socket definition expands out to four paths with two separate transport mechanisms - WebSockets and LongPolling. If we wanted to make sure that our channel is handled by only one type of transport, we could specify that using the `via` option, like this.\n\n```elixir\nsocket \"/ws\", HelloPhoenix do\n channel \"rooms:*\", RoomChannel, via: [Phoenix.Transports.WebSocket]\nend\n```\n\nIf we do this, `$ mix phoenix.routes` will still show the same four paths, because they are related to the socket, not the channel. Messages for the `\"rooms:*\"` topic, however, would all be handled exclusively over WebSockets.\n\nEach socket can handle requests for multiple channels.\n\n```elixir\nsocket \"/ws\", HelloPhoenix do\n channel \"rooms:*\", RoomChannel, via: [Phoenix.Transports.WebSocket]\n channel \"foods:*\", FoodChannel\nend\n```\n\nWe can also define multiple sockets for our application.\n\n```elixir\nsocket \"/ws\", HelloPhoenix do\n channel \"rooms:*\", RoomChannel, via: [Phoenix.Transports.WebSocket]\n channel \"foods:*\", FoodChannel\nend\n\nsocket \"/another_ws\", HelloPhoenix do\n channel \"news:*\", NewsChannel\nend\n```\n\nHere's what `$ mix phoenix.routes` says now.\n\n```console\n$ mix phoenix.routes\n. . .\nweb_socket_path GET /ws Phoenix.Transports.WebSocket.upgrade/2\nweb_socket_path POST /ws Phoenix.Transports.WebSocket.upgrade/2\nlong_poller_path GET /ws/poll Phoenix.Transports.LongPoller.poll/2\nlong_poller_path POST /ws/poll Phoenix.Transports.LongPoller.publish/2\nweb_socket_path GET /another_ws Phoenix.Transports.WebSocket.upgrade/2\nweb_socket_path POST /another_ws Phoenix.Transports.WebSocket.upgrade/2\nlong_poller_path GET /another_ws/poll Phoenix.Transports.LongPoller.poll/2\nlong_poller_path POST /another_ws/poll Phoenix.Transports.LongPoller.publish/2\n```\n\nEach socket gets four paths, two for WebSockets, two for LongPolling.\n\nLet's say we wanted all of the channels for a given socket to be handled by a single transport. We can accomplish that with the `via` option on the socket declaration itself, like this.\n\n```elixir\nsocket \"/another_ws\", HelloPhoenix, via: [Phoenix.Transports.WebSocket] do\n channel \"news:*\", NewsChannel\n channel \"pets:*\", PetChannel\nend\n```\n\nWhat if we want all the channels to be handled by WebSockets, except for one? That's easy as well. Just use the `via` option on the exceptional channel.\n\n```elixir\nsocket \"/another_ws\", HelloPhoenix, via: [Phoenix.Transports.WebSocket] do\n channel \"news:*\", NewsChannel\n channel \"pets:*\", PetChannel\n channel \"conversations:*\", ConversationChannel, via: [LongPoller]\nend\n```\n\n### Summary\n\nRouting is a big topic, and we have covered a lot of ground here. The important points to take away from this guide are:\n- Routes which begin with an HTTP verb name expand to a single clause of the match function.\n- Routes which begin with 'resources' expand to 8 clauses of the match function.\n- Resources may restrict the number of match function clauses by using the `only:` or `except:` options.\n- Any of these routes may be nested.\n- Any of these routes may be scoped to a given path.\n- Using the `as:` option in a scope can reduce duplication.\n- Using the helper option for scoped routes eliminates unreachable paths.\n- Scoped routes may also be nested.","updates":["54872fe0a8b5e31600952d37","5487303aa8b5e31600952d3a","54873228b3441a1f00f20dc5","5488d94df291f61400c02d0b","54a1654cce33cf1600c2336d","54a4f0054ebd6e0b0096c6e1","54beabde1bb6ed0c00af6265","54c22d1e421d1d0d004aa776","54f9c88cf2b25a2300d9d8ee","553b4795579cdf0d0028822d","5553c0e6d402b92300cee416","5553c1b67e64980d008d3f37","555f4ef4df54680d001803f2","5567a7660145bc23008e3c59","556d4d25d0f4740d00380c7e","557f4ef8eb75d80d00af4098","55b1f87ffa4acb1700910e8e","55b5ec5ac2e909190073eb0b"],"order":2,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"559218ad1da5250d001e9687","project":"54348ec95b10711400c6c445","githubsync":"","category":{"sync":{"isSync":false,"url":""},"pages":["559218ad1da5250d001e9684","559218ad1da5250d001e9685","559218ad1da5250d001e9686","559218ad1da5250d001e9687","559218ad1da5250d001e9688","559218ad1da5250d001e9689","559218ad1da5250d001e968a","559218ad1da5250d001e968b","559218ad1da5250d001e968c","559218ad1da5250d001e968d","559218ad1da5250d001e968e","559218ad1da5250d001e968f"],"title":"Guides","slug":"guides","order":1,"from_sync":false,"reference":false,"_id":"559218ad1da5250d001e9671","version":"559218ac1da5250d001e966f","__v":1,"createdAt":"2014-10-09T04:18:04.869Z","project":"54348ec95b10711400c6c445"},"user":"5435e00ad7d8700800bbec51","version":{"version":"0.14.0","version_clean":"0.14.0","codename":"","is_stable":false,"is_beta":true,"is_hidden":false,"is_deprecated":false,"categories":["559218ad1da5250d001e9670","559218ad1da5250d001e9671","559218ad1da5250d001e9672","559218ad1da5250d001e9673","559218ad1da5250d001e9674"],"_id":"559218ac1da5250d001e966f","releaseDate":"2015-06-30T04:18:52.132Z","__v":1,"createdAt":"2015-06-30T04:18:52.132Z","forked_from":"5558c642eb56ae2f00f714fc","project":"54348ec95b10711400c6c445"},"__v":3,"createdAt":"2014-12-03T22:03:45.802Z"}