Paralelismo Task e processo
# EX 1
def transaction(conn, params) do
# O exemplo abaixo inicia um processo, e não o espera, sem await, ótimo por exemplo quando se vai gerar um relatório que é muito demorado e precisa continuar a aplicação enquanto isso.
task = Task.start(fn -> Rocketpay.transaction(params) end)
conn
|> put_status(:no_content)
|> text("OK")
end
# EX 2
def transaction(conn, params) d
# O exemplo abaixo inicia um processo, e o espera, assim como no node com async await.
task = Task.async(fn -> Rocketpay.transaction(params) end)
with {:ok, %TransactionResponse{} = transaction} <- Task.await(task) do
conn
|> put_status(:ok)
|> render("transaction.json", transaction: transaction)
end
end
Todas as requests no Phoenix, são um processo isolado
Basic Auth
config/config.ex
config :rocketpay, :basic_auth,
username: "batata",
password: "batata123"
Router
pipeline :auth do
plug :basic_auth, Application.compile_env(:rocketpay, :basic_auth)
end
scope "/api", RocketpayWeb do
# pipe_through são regras para as rotas assim como app.use no node
pipe_through [:api, :auth]
post "/accounts/:id/deposit", AccountsController, :deposit
post "/accounts/:id/withdraw", AccountsController, :withdraw
post "/accounts/transaction", AccountsController, :transaction
end
Teste de Módulo
defmodule Rocketpay.Users.CreateTest do
# DataCase, o async: true serve para os testes rodarem mais rápido
use Rocketpay.DataCase, async: true
alias Rocketpay.Repo
alias Rocketpay.User
alias Rocketpay.Users.Create
describe "call/1" do
test "when all params are valid, return an user" do
params = %{
name: "Daniel",
password: "123456",
nickname: "dan",
email: "dan@email.com",
age: 20
}
{:ok, %User{id: user_id}} = Create.call(params)
user = Repo.get(User, user_id)
assert %User{name: "Daniel", age: 20, id: ^user_id} = user
end
test "when there are invalid params, return an error" do
params = %{
name: "Daniel",
nickname: "dan",
email: "dan@email.com",
age: 13
}
{:error, changeset} = Create.call(params)
expected_response = %{
age: ["must be greater than or equal to 18"],
password: ["can't be blank"]
}
assert errors_on(changeset) == expected_response
end
end
end
Teste de Controller
defmodule RocketpayWeb.AccountsControllerTest do
# ConnCase, o async: true serve para os testes rodarem mais rápido
use RocketpayWeb.ConnCase, async: true
alias Rocketpay.{Account, User}
describe "deposit/2" do
setup %{conn: conn} do
params = %{
name: "Daniel",
password: "123456",
nickname: "dan",
email: "dan@email.com",
age: 20
}
{:ok, %User{account: %Account{id: account_id}}} = Rocketpay.create_user(params)
# o user e senha decodificado = YmF0YXRhOmJhdGF0YTEyMw==
conn = put_req_header(conn, "authorization", "Basic YmF0YXRhOmJhdGF0YTEyMw==")
{:ok, conn: conn, account_id: account_id}
end
test "when all params are valid, make the deposit", %{conn: conn, account_id: account_id} do
params = %{"value" => "10.00"}
response =
conn
|> post(Routes.accounts_path(conn, :deposit, account_id, params))
|> json_response(:ok)
assert %{
"account" => %{"balance" => "10.00", "id" => _id},
"message" => "Balance changed sucessfully"
} = response
end
test "when there are invalid params, returns an error", %{conn: conn, account_id: account_id} do
params = %{"value" => "batata"}
response =
conn
|> post(Routes.accounts_path(conn, :deposit, account_id, params))
|> json_response(:bad_request)
expected_response = %{"message" => "Invalid operation value"}
assert response == expected_response
end
end
end
Teste de View (Não precisa testar a falha, pois a View só é renderizada quando a request é bem sucedida)