How can I make a macro for a controller, I want to login 2 different types of users UserClient, UserTransport that have many fields in common but are different, the login and the registration is basically the same in the controllers
defmodule PublitWeb.CliApiController do
use PublitWeb, :controller
alias Publit.{Repo, UserUtil, UserClient, SmsService}
# POST /cli_api/sessions
def create(conn, , %{"mobile_number" => mobile_number}) do
case UserUtil.set_mobile_verification_token(UserClient, mobile_number) do
{:ok, user} ->
render(conn, "show.json", user: user, sms_gateway: SmsService.sms_gateway_num())
_ ->
conn
|> put_status(:not_found)
|> render("error.json", msg: gettext("Mobile number not found"))
end
end
end
It would be nice to use the same macro like this
defmodule PublitWeb.CliApiController do
use PublitWeb.AuthControllerMacro, mod: Publit.UserClient
end
and for the UserTransport
defmodule PublitWeb.TransApiController do
use PublitWeb.AuthControllerMacro, mod: Publit.UserTransport
end
Couldn’t just have one general case function which implements the general case, and two specific functions which call it with fields set to their specific values?
I like the idea of moving the shared functionality into a separate module and then having the two controllers just call into that when needed, just to keep it simple, but I think behaviors might also work for your situation. If the two controllers share some actions but not others you could use behaviors like such:
defmodule ApiUserController do
# These are the functions that are different for each controller and must be
# implemented
@callback register(conn, params)
@callback login(conn, params)
defmacro __using__(_) do
quote do
@behaviour ApiUserController
# These are the functions that are shared across the different controller
# types, though they can be overridden if needed
def delete(conn, params) do ... end
def view(conn, params) do ... end
def whatever(conn, params) do ... end
defoverridable ApiUserController
end
end
end
# cli registration and login implemented here
defmodule CliApiController do
use PublitWeb, :controller
use ApiUserController
def register(conn, params) do ... end
def login(conn, params) do ... end
end
# transit registration and login implemented here
defmodule TransApiController do
use PublitWeb, :controller
use ApiUserController
def register(conn, params) do ... end
def login(conn, params) do ... end
end
I don’t know if this is the route I would take though, especially if there are only two different user types. If the controllers are very similar you could use a single controller for both, but have the registration/login endpoints point to different actions: create_api_user and create_tranport_user. Then move whatever shared functionality into private functions inside the controller that each would call.