Home Posts Post Search Tag Search

Ash Framework 05 - API's
Published on: 2025-09-27 Tags: elixir, Blog, Side Project, LiveView, Ecto, Html/CSS, Phoenix, Ash, Framework

Chapter 4: Generating APIs Without Writing Code

Modeling Your Domain

  • Goal: expose your domain so others can access it via REST or GraphQL
  • We’ll build both JSON REST and GraphQL interfaces

Building a JSON REST Interface

Setup

  • Use Igniter to install ash_json_api:

    mix igniter.install ash_json_api
  • This adds:

    • AshJsonApi Hex package
    • Code/config for application/vnd.api+json
    • TunezWeb.AshJsonApiRouter
    • New scope in Phoenix router

Adding Artists

  • Extend the Artist resource for the API:

    mix ash.extend Tunez.Music.Artist json_api
  • Adds AshJsonApi.Resource to Artist

  • Adds AshJsonApi.Domain extension for Tunez.Music

  • Connects domain to TunezWeb.AshJsonApiRouter

Routes

  • Set API routes in lib/tunez/music.ex:

    json_api do
      routes do
        base_route "/artists", Tunez.Music.Artist do
          get :read
          index :search
          post :create
          patch :update
          delete :destroy
        end
      end
    end
  • Check routes with:

    mix phx.routes
  • Example GET: http://localhost:4000/api/json/artists/?query=and

Public Attributes

  • Only attributes marked public? true are included in API responses

  • Example for Artist:

    attribute :previous_names, {:array, :string}, public?: true
    attribute :biography, :string, public?: true
  • Calculations/aggregates can be default fields or requested via query parameters:

    ?fields=name,album_count

Adding Albums

  • Extend the Album resource:

    mix ash.extend Tunez.Music.Album json_api
  • Set routes in lib/tunez/music.ex:

    base_route "/albums", Tunez.Music.Album do
      post :create
      patch :update
      delete :destroy
    end
  • Make necessary attributes public (name, year_released, cover_image_url)

  • Show related albums for an artist:

    relationships do
      has_many :albums, Tunez.Music.Album, public?: true, sort: [year_released: :desc]
    end
  • Include related records in API responses:

    json_api do
      type "artist"
      includes [:albums]
    end
  • Provide related links:

    related(:albums, :read, primary?: true)

Generating API Documentation

  • OpenAPI route:

    use AshJsonApi.Router, domains: [Tunez.Music], open_api: "/open_api"
  • Swagger UI available at /api/json/swaggerui in Phoenix router

Customizing the API

  • Add resource/action descriptions:

    resource do
      description "A person or group of people that makes and releases music."
    end
    
    read :search do
      description "List Artists, optionally filtering by name."
      argument :query, :ci_string, description: "Filter artists by name."
    end
  • Set API title and version in AshJsonApiRouter:

    open_api_title: "Tunez API Documentation",
    open_api_version: to_string(Application.spec(:tunez, :vsn))
  • Remove unwanted filters:

    derive_filter?(false)

Building a GraphQL Interface

Setup

  • Install ash_graphql via Igniter:

    mix igniter.install ash_graphql
  • Adds:

    • AshGraphql & Absinthe configuration
    • /gql pipeline & /gql/playground scope
    • TunezWeb.GraphqlSchema & TunezWeb.GraphqlSocket

Adding Artists

  • Extend Artist for GraphQL:

    mix ash.extend Tunez.Music.Artist graphql
  • Queries:

    graphql do
      queries do
        get Tunez.Music.Artist, :get_artist_by_id, :read
        list Tunez.Music.Artist, :search_artists, :search
      end
    end
  • Mutations:

    create Tunez.Music.Artist, :create_artist, :create
    update Tunez.Music.Artist, :update_artist, :update
    delete Tunez.Music.Artist, :destroy_artist, :destroy

Adding Albums

  • Extend Album for GraphQL:

    mix ash.extend Tunez.Music.Album graphql
  • Mutations for albums:

    create Tunez.Music.Album, :create_album, :create
    update Tunez.Music.Album, :update_album, :update
    destroy Tunez.Music.Album, :destroy_album, :destroy

Customizing GraphQL

  • Remove unwanted fields and set filterable fields:

    graphql do
      type :artist
      filterable_fields [:album_count, :cover_image_url, :inserted_at, :latest_album_year_released, :updated_at]
    end