Schema

Schema definition is stright forward, what's interesting here is changeset:

defmodule App1.Blog.Post do
  use Ecto.Schema
  import Ecto.Changeset

  schema "posts" do
    field :title, :string
    field :content, :string

    timestamps(type: :utc_datetime)
  end

  @doc false
  def changeset(post, attrs) do
    post
    |> cast(attrs, [:title, :content])
    |> validate_required([:title, :content])
  end
end

changeset from Ecto is for validation and transformation. It will called in context before inserting the data into database.

def create_post(attrs \\ %{}) do
  %Post{}
  |> Post.changeset(attrs)
  |> Repo.insert()
end

Try to call API with invalid request body:

curl -id '{"post": {}}' -H 'content-type: application/json'\
  localhost:4000/api/posts

Will return:

HTTP/1.1 422 Unprocessable Entity
...

{"errors":{"title":["can't be blank"],"content":["can't be blank"]}}