Elixir API 和 Elm SPA - 第一部分
第一部分:Elixir 应用创建
第一部分:Elixir 应用创建
我打算创建一个演示应用,后端使用 Elixir API,前端使用独立的 Elm 单页应用 (SPA)。该应用将是一个简单的 CRUD 应用,并遵循我目前总结的最佳实践。它将是一个简单的市场应用,用户可以在这里发布待售物品的信息,其他用户可以查看并购买。
该应用的名称为 Toltec。
系列
- 第一部分 - Elixir 应用创建
- 第二部分 - 添加监护人身份验证
- 第三部分:Elm 应用创建和路由设置
- 第四部分:添加登录和注册页面
- 第五部分:将会话数据持久化到本地存储
假设
我假设你使用的是:
- Elixir 1.6.5
- Erlang 20
- 榆树 0.18
- PostgreSQL 10.4
创建应用
让我们为 API 创建一个简单的应用程序。我们不需要 HTML 或 Brunch,因为我们根本不渲染 HTML。我们只需要公开一个 JSON REST API:
mix phx.new toltec-api --app toltec --no-brunch --no-html --binary-id
配置自动格式化
在添加任何代码之前,让我们先配置代码自动格式化。在项目根目录下添加一个名为.formatter.exs的文件:
# .formatter.exs
[
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
然后运行格式化命令:
mix format
这样应该可以格式化项目中的所有代码。
现在你需要配置编辑器,使其在保存文件时自动运行此命令。例如,对于 VS Code,你可以使用vscode-elixir和vscode-elixir-formatter扩展。
创建账户
我们将使用comeonin包来处理应用程序中的密码哈希。请在 mix.exs 文件中添加此依赖项。
# mix.exs
defp deps do
[
{:phoenix, "~> 1.3.0"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_ecto, "~> 3.2"},
{:postgrex, ">= 0.0.0"},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:comeonin, "~> 4.0"},
{:argon2_elixir, "~> 1.2"}
]
end
获取依赖项
mix deps.get
现在让我们添加用户架构和帐户上下文来保存所有这些逻辑。
mix phx.gen.context Accounts User users name:string email:string:unique password_hash:string
这将创建一个用户迁移、一个用户架构和一个账户上下文。对于用户,我不会使用 UUID 主键,因此我将从用户迁移中移除 binary_id 配置,但您可以根据需要保留它。
将迁移更改为:
# priv/repo/migrations/20180612062911_create_users.exs
def change do
execute("CREATE EXTENSION citext;")
create table(:users) do
add(:name, :string, null: false)
add(:email, :citext, null: false)
add(:password_hash, :string, null: false)
timestamps()
end
create(unique_index(:users, [:email]))
end
接下来,我们向用户模式添加一些基本方法:
# lib/toltec/accounts/user.ex
defmodule Toltec.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Toltec.Accounts.User
schema "users" do
field(:email, :string)
field(:name, :string)
field(:password, :string, virtual: true)
field(:password_hash, :string)
timestamps()
end
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:name, :email])
|> validate_required([:name, :email])
|> validate_length(:name, min: 2, max: 255)
|> validate_length(:email, min: 5, max: 255)
|> unique_constraint(:email)
|> validate_format(:email, ~r/@/)
end
def registration_changeset(%User{} = user, attrs) do
user
|> changeset(attrs)
|> cast(attrs, [:password])
|> validate_required([:password])
|> validate_length(:password, min: 8, max: 100)
|> put_password_hash()
end
defp put_password_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: password}} ->
put_change(changeset, :password_hash, Comeonin.Argon2.hashpwsalt(password))
_ ->
changeset
end
end
end
我添加了一个虚拟密码字段,用于临时存储明文密码。该密码永远不会保存到数据库中。我还添加了两个变更集,一个用于更改密码,另一个用于更改其他字段。`put_password_hash () ` 函数使用 comeonin 库获取密码的哈希值,并将其赋值给将要存储到数据库中的`password_hash`字段。
现在修改包含所有账户逻辑的账户上下文,使其如下所示:
# lib/toltec/accounts/accounts.ex
defmodule Toltec.Accounts do
import Ecto.Query, warn: false
alias Toltec.Repo
alias Toltec.Accounts.User
def list_users do
Repo.all(User)
end
def get_user!(id), do: Repo.get!(User, id)
def create_user(attrs \\ %{}) do
result =
%User{}
|> User.registration_changeset(attrs)
|> Repo.insert()
case result do
{:ok, user} -> {:ok, %User{user | password: nil}}
_ -> result
end
end
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update()
end
def delete_user(%User{} = user) do
Repo.delete(user)
end
def change_user(%User{} = user) do
User.changeset(user, %{})
end
end
接下来,让我们向数据库添加一些种子数据,使我们的应用程序可以使用。
# priv/repo/seeds.exs
# users
user =
Toltec.Accounts.User.registration_changeset(%Toltec.Accounts.User{}, %{
name: "some user",
email: "user@toltec",
password: "user@toltec"
})
Toltec.Repo.insert!(user)
现在是时候构建数据库、创建表并插入种子数据了。
mix ecto.reset
此命令会删除数据库(如果存在),然后重新创建数据库,按顺序运行迁移,最后运行 seeds.exs 文件插入初始数据。输出结果应该与此类似,并且不会出现任何错误。
mix ecto.reset
The database for Toltec.Repo has already been dropped
The database for Toltec.Repo has been created
[info] == Running Toltec.Repo.Migrations.CreateUsers.change/0 forward
[info] execute "CREATE EXTENSION citext;"
[info] create table users
[info] create index users_email_index
[info] == Migrated in 0.0s
[debug] QUERY OK db=2.8ms
INSERT INTO "users" ("email","name","password_hash","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["user@toltec", "some user", "$argon2i$v=19$m=65536,t=6,p=1$jdZHJ4HdGSF34hP6iTiPeQ$+PWBp77RP8wxMasVj0wv1wWS33pponixKSEG109V/u8", {{2018, 6, 12}, {22, 35, 55, 411334}}, {{2018, 6, 12}, {22, 35, 55, 411345}}]
您可以在此处仓库的 part-01 分支中找到源代码和测试。
克隆完成后,运行测试并验证一切是否正常:
mix test
...................
Finished in 0.3 seconds
19 tests, 0 failures
目前我们已经创建了应用程序、用户架构,并添加了一些初始用户来试用我们的应用程序。
暂时就这些。