I am creating an API with ruby on rails. I have got the basis of it done by following https://levelup.gitconnected.com/7-steps-to-create-an-api-in-rails-2f984c7c4286
but instead of Forests and trails, I am using restaurants and Comments as my models. Restaurants has many comments and comments has one restaurant - no user model for this.
But the show inside restaurants_controller.rb is this instead: (no controller for comments)
def show
@restaurant = Restaurant.find(params[:id])
@comments = @restaurant.comments
render json: @comments
end
Right now the link I have been testing is http://localhost:3000/restaurants/1
which creates a JSON with all comments for restaurant 1 (with separate IDs for each comment).
[
{
"id": 1,
"restaurant_id": 1,
"comment": "good.",
"age": 28,
"created_at": "2022-08-20T10:00:00.000Z",
"updated_at": "2022-08-20T10:00:00.000Z"
},
{
"id": 2,
"restaurant_id": 1,
"comment": "very good.",
"age": 25,
"created_at": "2022-08-20T12:30:00.000Z",
"updated_at": "2022-08-20T12:30:00.000Z"
}
]
What I want to do now is further search through that API by another attribute. Comments has another attribute called age that I would like to search through.
So now I want this: http://localhost:3000/restaurants/1/28
Which would show only the comments for restaurant 1 AND only by those aged 28.
intended output:
[
{
"id": 1,
"restaurant_id": 1,
"comment": "good.",
"age": 28,
"created_at": "2022-08-20T10:00:00.000Z",
"updated_at": "2022-08-20T10:00:00.000Z"
}
]
I am new to creating API's. Hope I've got the lingo correct here. Is this possible to do? I have not been able to find anything like this anywhere - probably searching for wrong key words
I did think about using another route? But that would then lead to something like http://localhost:3000/api/v1/restaurants/1/comments/28 which isn't want I want!
routes.rb
Rails.application.routes.draw do
resources :restaurants, only: [:index, :show, :create, :update]
end
CodePudding user response:
It could be done by configuring your routes, but this approach is brittle. What if next you wanted to get comments filtered by some other attribute (e.g. comment=~/good/
.
I think a better approach is to add a query string to carry the age query. The routes are not affected. So the http request would be something like:
http://localhost:3000/restaurant/1/comments?age=lt28
You would then decode the lt28
as "less than 28" on the server
or define a scope max_age
on the comments model and use a query like this:
http://localhost:3000/restaurant/1/comments?max_age=28
[update] after some more thought, I wanted to mention that the approach you're considering is not really conformant with the REST paradigm. Of course, REST is not "the law", and you can choose to ignore it, but with consideration.