Nested phoenix resources
Hi,
I've intercepted a problem that I couldn't find solution to. It concerns nested phoenix resources and documenting them with swagger macros.
It is possible to define nested resources in your router.
# router.ex
resources "/video-channels", VideoChannelController, only: [:show] do
resources "/videos", VideoController, only: [:index]
end
resources "/videos", VideoController, only: [:index]
By route definition like this I end up with having two index functions inside VideoController that are pattern matching different params.
# VideoController.ex
def VideoController do
use HelloWeb, :controller
use PhoenixSwagger
swagger_path :index do
get("/api/v1/video-channels/{video_channel_id}/videos")
description("Returns videos filtered by video channel.")
end
def index(conn, %{"video_channel_id" => video_channel_id} = params}) do
..list of videos filtered by video channel ID..
end
swagger_path :index do
get("/api/v1/videos")
description("Returns videos filtered by video channel.")
end
def index(conn, params) do
..list of videos...
end
end
Then during the compilation I get:
$ mix phx.swagger.generate
Compiling 2 files (.ex)
warning: this clause cannot match because a previous clause at line 20 always matches
*/video_controller.ex:87
The problem is that both swagger_paths are using the same action :index, although they handle completely different urls. Is this scenario supported? If it's not supported, is there some recommended workaround for nested resources then ?
Thank you
The only workaround so far I could come up with is not using nested resources, but rather define urls in router statically and use defdelegate to keep backward compatibility with nested resources if utilized again in the future:
# router.ex
resources "/video-channels", VideoChannelController, only: [:show]
get "/video-channels/:video_channel_id/videos", VideoController, :index_by_video_channel
resources "/videos", VideoController, only: [:index]
# VideoController.ex
def VideoController do
use HelloWeb, :controller
use PhoenixSwagger
defdelegate index_by_video_channel(conn, params),
to: VideoController,
as: :index
swagger_path :index_by_video_channel do
get("/api/v1/video-channels/{video_channel_id}/videos")
description("Returns videos filtered by video channel.")
end
def index(conn, %{"video_channel_id" => video_channel_id} = params}) do
..list of videos filtered by video channel ID..
end
swagger_path :index do
get("/api/v1/videos")
description("Returns videos filtered by video channel.")
end
def index(conn, params) do
..list of videos...
end
end