defmodule AshHqWeb.Pages.Home do @moduledoc "The home page" use Surface.LiveComponent alias AshHqWeb.Components.{CalloutText, CodeExample, SearchBar} alias Surface.Components.Form alias Surface.Components.Form.{Field, Submit, TextInput} import AshHqWeb.Components.CodeExample, only: [to_code: 1] import AshHqWeb.Tails prop device_brand, :string data signed_up, :boolean, default: false data email_form, :any data theme, :atom, default: :default def render(%{__context__: %{platform: :ios}} = assigns) do ~F""" Build and applications with a tool-chain. A declarative foundation for ambitious Elixir applications. Model your domain, derive the rest. """ end def render(assigns) do ~F"""
Build and applications with a tool-chain.
A declarative foundation for ambitious Elixir applications. Model your domain, derive the rest.

Framework

What is Ash?

Ash Framework is a declarative, resource-oriented application development framework for Elixir. A resource can model anything, like a database table, an external API, or even custom code. Ash provides a rich, and extensive set of tools for interacting with and building on top of these resources. By modeling your application as a set of resources, other tools know exactly how to use them, allowing extensions like AshGraphql and AshJsonApi to provide top tier APIs with minimal configuration. With filtering, sorting, pagination, calculations, aggregations, pub_sub, policy authorization, rich introspection, and much more built-in. Coupled with a comprehensive suite of tools to allow you to build your own extensions, the possibilities are endless.

Write it once

Why do developers keep reinventing the wheel?

Every time you start a new app, are you rebuilding features that you've already built many times? Wouldn't it be great if you could just focus on the important parts of an app without reinventing ways to authenticate, add permissions, etc. Ash allows you to not only use patterns in existing extensions, it lets you extract your own patterns into custom extensions. So when you need to do it again in a new application, it's already done. Just wire it up!

Consistency

A place for everything and everything in its place

Ash helps keep things neat and organized by providing good patterns for structuring your application. Over time and with larger teams of different experience levels, patterns change and drift away from each-other across our applications. With that said, nothing in Ash depends on what folders or files you put things in, so you are free to experiment or make the choices that make sense to you.

Spaghetti belongs in the kitchen, not in your codebase. Ash provides the ability to keep all similar parts of your application consistent, making it easy to share an architectural vision while allowing escape hatches to do something different if needed.

Incredibly Powerful

Ash is more than it appears

Ash is more than just auto-generated API or an Admin UI. It’s a fully extensible DSL to model your domain, which creates a declarative, highly introspectable representation. This in turn can be used to derive anything you want.

Ash has built in extensions that allow you to generate Admin UIs or Phoenix LiveView Form helpers, saving a ton of boilerplate. Even going as far as fully swapping data layers, Ash lets you do something traditionally extremely difficult with ease.

Brought to you by

"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!

Become a contributor
{#if @signed_up} Thank you for joining our mailing list! {#else}

Join our mailing list for (tastefully paced) updates!

Join
{/if}

Paid Support

can help

Alembic offers expert support to help you overcome any challenges and ensure the success of your project. Our team has extensive knowledge and experience with Ash Framework, as well as the larger Elixir ecosystem and can provide personalized assistance to help you build products, implement new features, or improve your existing codebases. Contact us to learn more about our support options and how we can help your project succeed.

""" end def mount(socket) do {:ok, assign( socket, signed_up: false, email_form: AshPhoenix.Form.for_create(AshHq.MailingList.Email, :create, api: AshHq.MailingList, upsert?: true, upsert_identity: :unique_email ) )} end def handle_event("toggle-theme", _, socket) do if socket.assigns.theme == :default do {:noreply, assign(socket, :theme, :dark)} else {:noreply, assign(socket, :theme, :default)} end end def handle_event("validate_email_form", %{"form" => form}, socket) do {:noreply, assign(socket, email_form: AshPhoenix.Form.validate(socket.assigns.email_form, form))} end def handle_event("submit_email_form", _, socket) do case AshPhoenix.Form.submit(socket.assigns.email_form) do {:ok, _} -> {:noreply, assign(socket, :signed_up, true)} {:error, form} -> {:noreply, assign(socket, email_form: form)} end end @changeset_example """ 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) |> Example.read!() """ |> to_code() defp changeset_example do @changeset_example end @live_view_example """ 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 """ |> to_code() defp live_view_example do @live_view_example end @graphql_example """ 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 """ |> to_code() defp graphql_example do @graphql_example end @policies_example """ policies do policy action_type(:read) do authorize_if expr(visibility == :everyone) authorize_if relates_to_actor_via([:author, :friends]) end end """ |> to_code() defp policies_example do @policies_example end @notifier_example """ pub_sub do module ExampleEndpoint prefix "post" publish_all :create, ["created"] publish :react, ["reaction", :id] event: "reaction" end """ |> to_code() defp notifier_example do @notifier_example end @aggregate_example """ 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 """ |> to_code() defp aggregate_example do @aggregate_example end @post_example """ defmodule Example.Post do use AshHq.Resource, 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 """ |> to_code() defp post_example do @post_example end end