Service delivery partner
Alembic specializes in providing Ash Framework consulting services. We offer custom development solutions and implementation guidance through our Ash Premium Support service. With extensive knowledge of both Ash Framework and the broader Elixir ecosystem, our team of Ash experts is well-equipped to make your project excel.
"The ease of defining our domain model and configuring Ash to generate a powerful GraphQL API has been a game-changer. What used to be complex and time-consuming has become simplicity itself."
Alan Heywood
CTO, HereTask
"Through its declarative extensibility, Ash delivers more than you'd expect: Powerful APIs with filtering/sorting/pagination/calculations/aggregations, pub/sub, authorization, rich introspection, GraphQL... It's what empowers this solo developer to build an ambitious ERP!"
Frank Dugan III
System Specialist, SunnyCor Inc.
"I’m constantly blown away with the quality of work and support the Ash community has put into this project. It’s gotten to the point that I can’t imagine starting a new Elixir project that doesn’t use Ash."
Brett Kolodny
Full stack engineer, MEW
"Ash is an incredibly powerful idea that gives Alembic a massive competitive advantage. It empowers us to build wildly ambitious applications for our clients with tiny teams, while consistently delivering the high level of quality that our customers have come to expect."
Josh Price
Technical Director, Alembic
"Ash Framework enabled us to build a robust platform for delivering financial services using bitcoin. Ash proved itself to our team by handling innovative use cases with ease and it continues to evolve ahead of our growing list of needs."
Yousef Janajri
CTO & Co-Founder, Coinbits
"The more I’ve used Ash, the more blown away I am by how much I get out of it – and how little boilerplate I have to write. I’m yet to encounter a situation where I would need to fight the “Ash way” of doing things, but the framework still allows me to choose how I build my software."
Juha Lehtonen
Senior Software Developer
It wouldn't be possible without our amazing community.
175 contributors
and counting!
Define a resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
defmodule Example.Post do
use Ash.Resource,
domain: Example,
data_layer: AshPostgres.DataLayer
resource do
description "A post is the primary sharable entity in our system"
end
postgres do
table "posts"
repo Example.Repo
end
attributes do
attribute :text, :string do
allow_nil? false
description "The body of the text"
end
attribute :visibility, :atom do
constraints [
one_of: [:friends, :everyone]
]
description "Which set of users this post should be visible to"
end
end
actions do
update :react do
argument :type, Example.Types.ReactionType do
allow_nil? false
end
change manage_relationship(
:type,
:reactions,
type: :append
)
end
end
relationships do
belongs_to :author, Example.User do
allow_nil? true
end
has_many :reactions, Example.Reaction
end
end
1
2
3
4
5
6
7
8
9
10
post = Example.Post.create!(%{
text: "Declarative programming is fun!"
})
Example.Post.react!(post, %{type: :like})
Example.Post
|> Ash.Query.filter(likes > 10)
|> Ash.Query.sort(likes: :desc)
|> Ash.read!()
1
2
3
4
5
6
7
8
9
10
11
12
13
graphql do
type :post
queries do
get :get_post, :read
list :feed, :read
end
mutations do
create :create_post, :create
update :react_to_post, :react
end
end
policies do
policy action_type(:read) do
authorize_if expr(visibility == :everyone)
authorize_if relates_to_actor_via([:author, :friends])
end
end
aggregates do
count :likes, :reactions do
filter expr(type == :like)
end
count :dislikes, :reactions do
filter expr(type == :dislike)
end
end
calculations do
calculate :like_ratio, :float do
expr(likes / (likes + dislikes))
end
end
pub_sub do
module ExampleEndpoint
prefix "post"
publish_all :create, ["created"]
publish :react, ["reaction", :id] event: "reaction"
end
def mount(_params, _session, socket) do
form = AshPhoenix.Form.for_create(Example.Post, :create)
{:ok, assign(socket, :form, form)}
end
def handle_event("validate", %{"form" => input}, socket) do
form = AshPhoenix.Form.validate(socket.assigns.form, input)
{:ok, assign(socket, :form, form)}
end
def handle_event("submit", _, socket) do
case AshPhoenix.Form.submit(socket.assigns.form) do
{:ok, post} ->
{:ok, redirect_to_post(socket, post)}
{:error, form_with_errors} ->
{:noreply, assign(socket, :form, form_with_errors)}
end
end