Data Layer
This layer communicates with the GraphQL layer via a Service Context object. It is responsible for interacting with databases and object stores.
Services
In Potionx, we call modules that create, fetch, edit and delete models Services
. The GraphQL layer calls these Services
to respond to GraphQL requests from the web layer.
For example, here's an example of a User service similar to services generated by the model generator:
defmodule SomeProject.Users.UserService do
alias Potionx.Context.Service
alias SomeProject.Users.User
alias SomeProject.Repo
import Ecto.Query
def count(%Service{} = ctx) do
from(item in query(ctx), select: count(item.id))
|> Repo.one!
end
def delete(%Service{} = ctx) do
query(ctx)
|> Repo.one
|> case do
nil -> {:error, "not_found"}
entry ->
entry
|> Repo.delete
end
end
def mutation(%Service{filters: %{id: id}} = ctx) when not is_nil(id) do
query(ctx)
|> Repo.one
|> case do
nil -> {:error, "not_found"}
entry ->
User.changeset(entry, ctx.changes)
|> Repo.update
end
end
def mutation(%Service{} = ctx) do
%User{}
|> User.changeset(ctx.changes)
|> Repo.insert
end
def one(%Service{} = ctx) do
query(ctx)
|> Repo.one
end
def query(%Service{} = ctx) do
User
|> where(
^(
ctx.filters
|> Map.to_list
)
)
end
def query(q, _args), do: q
end
Service Context
The Service Context module (Potionx.Context.Service
) represents the message format that the data layer expects to receive. The GraphQL layer converts inputs received from the web layer into Service Context messages that are then passed to the data layer.
Here's an example of a message:
%Potionx.Context.Service{
changes: %{
name_first: "John",
name_last: "Smith"
},
files: [
%Plug.Upload{
content_type: "image/jpg",
filename: "john-smith.png",
path: "/tmp/john-smith.png"
}
],
filters: %{
id: "AWZPR3"
},
roles: [:admin],
user: %SomeProject.Users.User{
# ...user fields
}
}
File and Folder Naming Conventions
Potionx tries follows Phoenix's Contexts framework for naming folders. Individual model files follow Phoenix's guidelines as well. Potionx differs in how it handles naming modules responsible for manipulating models. In Potionx these are called "Services" and follows the file naming convention: "model_service.ex".
For example, files for a User model would include:
user_service.ex
where the module is calledSomeProject.Users.UserService
.user.ex
where the module is calledSomeProject.Users.User
.