sangeethailango

sangeethailango

How to use URL placeholders in action?

Given I have a nested resource with articles having many comments, how do I create an API endpoint for posting comments.
I want my API for creating comments at POST /articles/:id/comments. How do I create this nested API structure?
My resource for Articles and Comments are shown below:

Article resource:

defmodule Account.Blog.Article do
  use Ash.Resource,
    domain: Account.Blog,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshJsonApi.Resource]

  alias Account.Blog.Comment

  postgres do
    table "articles"
    repo Account.Repo
  end

  json_api do
    type "article"
  end

  actions do
    defaults [:read]

    create :article do
      accept [:name]
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :name, :string
  end

  relationships do
    has_many :comments, Comment
  end
end

Comments resource

defmodule Account.Blog.Comment do
  use Ash.Resource,
    domain: Account.Blog,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshJsonApi.Resource]

  alias Account.Blog.Article

  postgres do
    table "comments"
    repo Account.Repo
  end

  json_api do
    type "comment"
  end

  actions do
    defaults [:read]

    create :comment do
      accept [:comment, :article_id]
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :comment, :string
  end

  relationships do
    belongs_to :article, Article
  end
end

Domain:

defmodule Account.Blog do
  use Ash.Domain,
    extensions: [AshJsonApi.Domain]

  alias Account.Blog.{Article, Comment}

  resources do
    resource Article
    resource Comment
  end

  json_api do
    routes do
      base_route "/articles", Article do
        get(:read)
        post(:article)
      end

      base_route "/comments", Comment do
        get(:read)
        post(:comment)
      end
    end
  end
end

I am currently giving the request at POST /comments with the article_id to mention which article the comments belongs to.

Example:

{
    "data": {
        "type": "comment",
        "attributes": {
            "comment": "Good",
            "article_id": "article_id"
        }
    }
}

Marked As Solved

zachdaniel

zachdaniel

Creator of Ash

You should be able to do that by including an article_id in the route params for your post.

# include at top level
post Post, :create, route: "/articles/:article_id/comments"

Your post pointed out to me that being able to nest base_routes could clean this up greatly, so I’m pushing a release w/ that ability soon. Then it would look like this:

defmodule Account.Blog do
  use Ash.Domain,
    extensions: [AshJsonApi.Domain]

  alias Account.Blog.{Article, Comment}

  resources do
    resource Article
    resource Comment
  end

  json_api do
    routes do
      base_route "/articles", Article do
        get(:read)
        post(:article)

        base_route "/:article_id", Comment do
          post :comment # would call the `:comment` create action on comment
        end
      end

      base_route "/comments", Comment do
        get(:read)
        post(:comment)
      end
    end
  end
end

Also Liked

zachdaniel

zachdaniel

Creator of Ash

related is a route for reading the records of a relationship, i.e

/posts/:id/comments

It can be thought of as an index route that only returns the related records.

post_to_relationship is for “linking” a record or records to another via a relationship. It accepts a very specific input (something called “linkage”), and is typically only used to connect existing things together.

You can see more here: JSON:API — Latest Specification (v1.1)

shankardevy

shankardevy

wow @zachdaniel that’s super fast! You comment here is 18hours ago and I see this commit implementing this feature17hrs ago! improvement: support nested `base_route`s · ash-project/ash_json_api@bf77d4d · GitHub

This is something I was also looking for as well. However, I would like to understand the difference between using related or post_to_relationship macro inside the routes vs what you have proposed as a new solution here:

For eg., can the following do the same as what you have proposed as nested base_route for creating comment?

  json_api do
    routes do
      base_route "/articles", Article do
         post_to_relationship :comments
      end
end
shankardevy

shankardevy

Just to clarify, please check if my understanding is correct:

1. related option on routes

Use this only for GET requests for related records. Doesn’t work for any other methods.

If Article resource has many Tag relationship, this related option is used to fetch only the associated tags of a specific article.

In this case, the Ash action for the api is placed in the Article resource.

2. post_to_relationship option on routes

Use this option for any other methods other than GET for related records. The related record must already exist. In the case of Article and Tag relationships, both the records must exist already. post_to_relationship is used to create the linkage in ArticleTags resource.

The same applies for patch_relationship, delete_from_relationship to update or delete the link ArticleTags resource record.

In this case, the Ash action for the api is placed in the Article resource.

3. Nested base_route as explained in this post by @zachdaniel

Use this option to do any of the above actions with the main differences as below:

  1. Ash action for the nested route is present in the nested resource rather than in the parent resource as in the above options. i.e., GET /articles/:id/tags will be responded by an action in the Tag resource.
  2. In the nested resource, one has to take care of creating/updating/deleting all the links manually.

Is my understanding correct?

Where Next?

Popular in Questions Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127089 1222
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement