Ruby on Rails API-only with Nested Resources

vshl

Vishal

Posted on August 6, 2020

Ruby on Rails API-only with Nested Resources

As part of an interview coding challenge, I was asked to create a simple backend API that returned a list of doctors and their appointments. Before this challenge, I only knew in theory how to create an API-only app in Ruby on Rails and I believe I had followed through a tutorial to create a simple API. This post will cover what I learned from going through the process of reading the Rails documentation and understanding the requirements from the challenge given to me.

First and foremost is to create a Rails API-only app:

$ bundle exec rails new doctors_api --api

The idea will be to create a Rails API with the following routes at the minimum:

GET api/v1/doctors

GET api/v1/doctors/1

POST api/v1/doctors

DELETE api/v1/doctors/1

GET api/v1/doctors/1/appointments

POST api/v1/doctors/1/appointments

DELETE api/v1/doctors/1/appointments/1

Security and authentication protocols aside, this should allow any client to create, view or delete a doctor or appointment resource.

Models

Once the application is ready, next step will be to create a data model and controller for Doctor and Appointment.

$ bundle exec rails g scaffold Doctor first_name:string last_name:string

$ bundle exec rails g scaffold Appointment first_name:string last_name:string visit:datetime

$ bundle exec rails db:create

$ bundle exec rails db:migrate

In app/models/doctor.rb

class Doctor < ApplicationRecord
  has_many :appointments, dependent: :destroy
end

In app/models/appointment.rb

class Appointment < ApplicationRecord
  belongs_to :doctor
end

Controllers

It’s recommended to organize your API controllers, at best we will move them to their own directory. In this example we move the appointments and doctors controller ruby files to an API directory.

mv app/controllers/*.rb app/controllers/api/v1

The controllers will be doing the brunt of the work of processing the requests using the index, show, create, update, and destroy methods.

Seeding the database

In db/seeds.rb, we will seed sample data to ensure the REST endpoints work as designed.

Doctor.create(first_name: 'John', last_name: 'Smith')
doctor = Doctor.first
Appointment.create(doctor_id: doctor.id, patient_first_name: 'Jane', patient_last_name: 'Doe', visit: 2.hours.ago)
Appointment.create(doctor_id: doctor.id, patient_first_name: 'Jack', patient_last_name: 'Doe', visit: 1.day.ago)

bundle exec rails db:seed will insert the records into the database.

Testing

In a web browser or a REST client, now you test the endpoints

GET api/v1/doctors/1


GET api/v1/doctors/1

GET api/v1/doctors/1/appointments


GET api/v1/doctors/1/appointments

Creating new records for Doctor and Appointment will accept a JSON payload as a POST request

POST api/v1/doctors


POST api/v1/doctors

Conclusion

In the end, we achieved our simple goal of a nested REST API. To improve on this setup, in the front-end we can sanitize the inputs before sending requests, insert client information in the HTTP headers to be authenticated in the backend. An example for such an effort is to ensure doctors can only view their own appointments.

Full discretion, while this post has largely been a learning exercise, a full scale REST API will have it’s own set of complexities and design principles that isn’t covered here. Stay tuned for more posts in the future as and when I encounter similar and complex problems in the backend software engineering space.

💖 💪 🙅 🚩
vshl
Vishal

Posted on August 6, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related