Search code examples
ruby-on-railsrestapi-designruby-on-rails-6

Rails Best API design to get all of a record associated with a certain user


This is mostly an api design question. I have a Rails api which has routes for Users and routes for Schools. I would like to make a single call from my front end application to the api with a param of UserId which returns all of the schools associated with that user.

What is the best way to do that? Should I create a new route in UsersController called user-schools? Or a new route in SchoolsController called schools-user? Or create an entirely new controller called user-schools? Thanks for any guidance!

PS: Getting the records from ActiveRecord in the controller is not the problem. The problem is how to best design this api.


Solution

  • The RESTful way to define this would be through a nested route:

    GET /users/:user_id/schools
    

    The same basic design principles apply here for API and "classic" applications.

    You can define this by nesting the calls to the resources macro:

    resources :users do
      resources :schools, only: [:index]
    end
    

    This will route /users/:user_id/schools to SchoolsController#index. While you can "sniff" for the user_id param:

    class SchoolsController
      # GET /schools
      # GET /users/1/schools
      def index
        schools = if params[:user_id].present?
          user = User.find(params[:user_id])
          user.schools 
        else
          School.all
        end
        render json: schools
      end
    end
    

    A cleaner design is to use a seperate controller for the nested context:

    resources :users do
      resources :schools, only: [:index], module: :users
    end
    
    module Users
      class SchoolsController < ApplicationController
        # GET /users/1/schools
        def index
          user = User.find(params[:user_id])
          render json: user.schools
        end
      end
    end
    

    This controller only does a single job. You could also name it UserSchoolsController but splitting your controllers into folders (and namespaces) makes it easier to organize them.