Troubleshooting JSON API - curl resulting in 404

I am working through Getting Started With Json Api — ash_json_api v0.34.2 but can’t get it working. When I do a curl http://localhost:4000/api/json/tasks I get a 404. How can I debug/fix this?

[info] GET /api/json/tasks
[debug] Processing with AppWeb.Api.Router
  Parameters: %{}
  Pipelines: [:api]
[info] Sent 404 in 11ms
iex(1)>

Here’s my resource:

defmodule App.ToDoList.Task do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshJsonApi.Resource]

  postgres do
    table "tasks"
    repo App.Repo
  end

  attributes do
    uuid_primary_key :id
    attribute :content, :string, allow_nil?: false
    attribute :position, :integer, allow_nil?: false
  end

  actions do
    defaults [:create, :read, :update, :destroy]
  end

  code_interface do
    define_for App.ToDoList
    define :read
    define :create
    define :update
    define :destroy
    define :by_id, get_by: [:id], action: :read
  end

  json_api do
    type "task"

    routes do
      base("/tasks")
      get(:read)
      index :read
      post(:create)
      patch(:update)
    end
  end
end

This is part of my normal router.ex:

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api/json" do
    pipe_through(:api)

    forward "/tasks", AppWeb.Api.Router
  end

This is a new file:

defmodule AppWeb.Api.Router do
  use AshJsonApi.Api.Router,
    # The api modules you want to serve
    apis: [App.ToDoList],
    # optionally a json_schema route
    json_schema: "/json_schema",
    # optionally an open_api route
    open_api: "/open_api"
end

Debug Info:

iex(1)> App.ToDoList.Task |> AshJsonApi.Resource.Info.routes()
[
  %AshJsonApi.Resource.Route{
    route: "/tasks/:id",
    action: :read,
    action_type: :read,
    default_fields: nil,
    method: :get,
    controller: AshJsonApi.Controllers.Get,
    relationship: nil,
    type: :get,
    primary?: false,
    upsert?: nil,
    upsert_identity: nil,
    read_action: nil,
    relationship_arguments: []
  },
  %AshJsonApi.Resource.Route{
    route: "/tasks",
    action: :read,
    action_type: :read,
    default_fields: nil,
    method: :get,
    controller: AshJsonApi.Controllers.Index,
    relationship: nil,
    type: :index,
    primary?: false,
    upsert?: nil,
    upsert_identity: nil,
    read_action: nil,
    relationship_arguments: []
  },
  %AshJsonApi.Resource.Route{
    route: "/tasks",
    action: :create,
    action_type: :create,
    default_fields: nil,
    method: :post,
    controller: AshJsonApi.Controllers.Post,
    relationship: nil,
    type: :post,
    primary?: false,
    upsert?: false,
    upsert_identity: false,
    read_action: nil,
    relationship_arguments: []
  },
  %AshJsonApi.Resource.Route{
    route: "/tasks/:id",
    action: :update,
    action_type: :update,
    default_fields: nil,
    method: :patch,
    controller: AshJsonApi.Controllers.Patch,
    relationship: nil,
    type: :patch,
    primary?: false,
    upsert?: nil,
    upsert_identity: nil,
    read_action: nil,
    relationship_arguments: []
  }
]
  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api/json" do
    pipe_through(:api)

   #  forward "/tasks", AppWeb.Api.Router
    forward "/", AppWeb.Api.Router # <- use this
  end

By forwarding /tasks in that scope to the api router, you’re putting the routes at /api/json/tasks/<resource_routes>

1 Like

You can always run mix phx.routes to dump the routes table to your console. It can be very helpful in debugging!

An unfortunate thing is that routes in forwarded to routers do not show up in mix phx.routes :frowning:

90c