Hello. I have a question about design of phoenix api server.
I am developing a web application, and using phoenix as a backend server for it. I saw some open source repositories as examples, but I still don’t know what is a good way to determine a design. I will take papercups chat api as an example of phoenix server.
Question
I think phoenix consists of controller
, view
, and schema
file, query
file. In the below examples, elixir reads information from database with query and schema, pass the information to controller, and shape it as a json in the view. The view returns most of user
information except for preloaded data such as settings
, profile
, then I got 2 questions of it.
-
Should API Server only provide information which is required by front-end as a response?
The view contains most ofuser
information as I said. Although I’m not sure how the front-end is, I don’t think the all fields ofrender("user.json", %{user: user})
are necessary in all cases to handle user information in front-end. Do I not need to prepare a view per a kind of request from front-end? -
Should I refrain from frequent use of preload?
get_user_info/2
returns not onlyuser
information but also preloaded data. But the preloaded data are unused in view. Should I prepare another function which does not preload data In such case? Or does it depend on information like table size, count of foreign keys, and so on?
Query
@spec get_user_info(binary(), integer()) :: User.t() | nil
def get_user_info(account_id, user_id) do
User
|> where(id: ^user_id, account_id: ^account_id)
|> Repo.one()
|> Repo.preload([:profile, :settings])
end
Schema
schema "users" do
field(:email_confirmation_token, :string)
field(:password_reset_token, :string)
field(:email_confirmed_at, :utc_datetime)
field(:disabled_at, :utc_datetime)
field(:archived_at, :utc_datetime)
field(:role, :string, default: "user")
field(:has_valid_email, :boolean)
has_many(:conversations, Conversation, foreign_key: :assignee_id)
has_many(:messages, Message, foreign_key: :user_id)
belongs_to(:account, Account, type: :binary_id)
has_one(:profile, UserProfile)
has_one(:settings, UserSettings)
has_many(:mentions, Mention)
has_many(:mentioned_conversations, through: [:mentions, :conversation])
has_many(:mentioned_messages, through: [:mentions, :message])
pow_user_fields()
timestamps()
end
Controller
@spec show(Plug.Conn.t(), map) :: Plug.Conn.t()
def show(conn, %{"id" => id}) do
user = ChatApi.Users.get_user_info(conn.assigns.current_user.account_id, id)
render(conn, "show.json", user: user)
end
View
def render("show.json", %{user: user}) do
%{data: render_one(user, UserView, "user.json")}
end
def render("user.json", %{user: user}) do
case user do
%{profile: %UserProfile{} = profile} ->
%{
id: user.id,
object: "user",
email: user.email,
created_at: user.inserted_at,
disabled_at: user.disabled_at,
archived_at: user.archived_at,
full_name: profile.full_name,
display_name: profile.display_name,
profile_photo_url: profile.profile_photo_url,
role: user.role
}
_ ->
%{
id: user.id,
object: "user",
email: user.email,
created_at: user.inserted_at,
disabled_at: user.disabled_at,
archived_at: user.archived_at,
role: user.role
}
end
end
Thank you.