話說進行到了第二十篇還停在 Router,我幾乎要確定三十篇寫不完想講的東西了。一定是之前碎念太多了。今天要來繼續談 Router 的其它功能。
在 Router 中,我們可以用 scope 來分組不同的 URI 路徑。來打開 router.ex 檔案,將最底下的 scope "/api"
區塊的註釋移除,加上 .API
及 as: :api
。在區塊裡放進一個 get
及一個 resources
,變成這樣:
scope "/api", HelloPhxWeb.API, as: :api do
pipe_through :api
get "/", DocController, :index
resources "/users", UsersController
end
回到 shell,用 mix phx.routes
指令就會看到生出這樣的 routes:
api_doc_path GET /api HelloPhxWeb.API.DocController :index
api_user_path GET /api/users HelloPhxWeb.API.UserController :index
api_user_path GET /api/users/:id/edit HelloPhxWeb.API.UserController :edit
api_user_path GET /api/users/new HelloPhxWeb.API.UserController :new
api_user_path GET /api/users/:id HelloPhxWeb.API.UserController :show
api_user_path POST /api/users HelloPhxWeb.API.UserController :create
api_user_path PATCH /api/users/:id HelloPhxWeb.API.UserController :update
PUT /api/users/:id HelloPhxWeb.API.UserController :update
api_user_path DELETE /api/users/:id HelloPhxWeb.API.UserController :delete
重點在於放在 scope do...end
區塊內的 URI,都是對於 scope
第一個參數的相對路徑。
由於 scope 裡可以用 pipe_throigh
來決定這群 URI 要流過的 pipeline,所以實務上最常用來劃分不同功能的群組,舉例來說,如果有公開的頁面、需要登入的頁面跟管理者的後台,可能會這樣劃分:
scope "/" do
pipe_through :browser
#...
end
scope "/dashboard" do
pipe_through [:browser, :auth]
end
scope "/admin" do
pipe_through [:browser, :auth, :check_admin]
end
由於 mix phx.gen.html
會把 view 及 controller 直接放在 lib/專案名稱_web/view
及 lib/專案名稱_web/controller
根目錄下,所以如果要依 scope 的名稱來組織檔案夾的話,可以使用 --web
參數:
$ mix phx.gen.html Admin Dashboard dashboards --web Admin
除了網頁表單的 CRUD 之外,Phoenix 也提供了生成 API CRUD 指令:
$ mix phx.gen.json API User users name:string age:integer --web API
* creating lib/hello_phx_web/controllers/api/user_controller.ex
* creating lib/hello_phx_web/views/api/user_view.ex
* creating test/hello_phx_web/controllers/api/user_controller_test.exs
* creating lib/hello_phx_web/views/changeset_view.ex
* creating lib/hello_phx_web/controllers/fallback_controller.ex
* creating lib/hello_phx/api/user.ex
* creating priv/repo/migrations/20180115185210_create_users.exs
* creating lib/hello_phx/api/api.ex
* injecting lib/hello_phx/api/api.ex
* creating test/hello_phx/api/api_test.exs
* injecting test/hello_phx/api/api_test.exs
Add the resource to your API :api scope in lib/hello_phx_web/router.ex:
scope "/api", HelloPhxWeb.API do
pipe_through :api
...
resources "/users", UserController
end
Remember to update your repository by running migrations:
$ mix ecto.migrate
跑完 mix ecto.migrate
後,用瀏覽器打開 http://localhost:4000/api/users
,就能看到 JSON 的回傳值了:
如果要產生巢狀的 routes,只要這樣做就可以了:
resources "/users", UserController do
resources "/posts", PostController
end
這樣就會產生以下的路由:
user_post_path GET /users/:user_id/posts HelloWeb.PostController :index
user_post_path GET /users/:user_id/posts/:id/edit HelloWeb.PostController :edit
user_post_path GET /users/:user_id/posts/new HelloWeb.PostController :new
user_post_path GET /users/:user_id/posts/:id HelloWeb.PostController :show
user_post_path POST /users/:user_id/posts HelloWeb.PostController :create
user_post_path PATCH /users/:user_id/posts/:id HelloWeb.PostController :update
PUT /users/:user_id/posts/:id HelloWeb.PostController :update
user_post_path DELETE /users/:user_id/posts/:id HelloWeb.PostController :delete
要注意的是這個例子中上層的路由的參數名稱,會變成 :user_id
,此名稱是由其 resource 名稱決定的。
當我們用 mix phx.routes
來看產生出的路由時,每行的第一個名稱是在程式裡用來產生路徑字串的 helper 函式。我們來試試看:
iex> import HelloPhx.Router.Helpers
iex> alias HelloPhx.Endpoint
iex> api_user_path(Endpoint, :index)
"/api/users"
iex> api_user_path(Endpoint, :show, 17)
"/api/users/17"
iex> api_user_path(Endpoint, :new)
"/api/users/new"
這個路徑 helper 通常用在 View 、Template 或是 Controller 中來產生要前往的頁面路徑。如果你想要改變這個 helper 函式的名稱時,可以使用 :as
選項:
scope "/api", HelloPhxWeb.API, as: :v1 do
resources "/users", UsersController
end
會產生出
v1_user_path GET /api/users HelloPhxWeb.API.UserController :index
v1_user_path GET /api/users/:id/edit HelloPhxWeb.API.UserController :edit
...
pipe_through/1
來選擇要流經的 pipelinedo...end
區塊裡as:
選項可以改變 helper 函式的名稱Happy hacking! 明天見。