Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement API Root and Status Endpoints #10

Merged
merged 3 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions app/controllers/api/v1/root_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

# app/controllers/api/v1/root_controller.rb
module Api
module V1
# RootController is responsible for handling the root endpoint of the API.
# It provides a welcome message and a list of available endpoints.
#
class RootController < ApplicationController
skip_before_action :verify_authentication_credentials!

# rubocop:disable Metrics/MethodLength

# GET /api/v1
#
# This method is responsible for rendering a welcome message and a
# list of available endpoints
# in the Product Management Service API.
#
# ==== Returns
#
# JSON:
# - message: Welcome message to the Product Management Service API
# - version: API version
# - documentation: Link to the API documentation
# - available_endpoints: Hash containing the available endpoints
#
def index
render json: {
message: 'Welcome to the Product Management Service API',
version: 'v1',
base_url: "#{request.base_url}/api/v1",
documentation: 'https://documenter.getpostman.com/view/' \
'14404907/2sAXjRWpnZ',
available_endpoints: {
products: '/api/v1/products',
categories: '/api/v1/categories',
carts: '/api/v1/cart',
orders: '/api/v1/orders',
status: '/api/v1/status'
}
}, status: :ok
end

# rubocop:enable Metrics/MethodLength
end
end
end
43 changes: 43 additions & 0 deletions app/controllers/api/v1/status_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

module Api
module V1
# Controller for API status information
class StatusController < ApplicationController
skip_before_action :verify_authentication_credentials!
before_action :ensure_database_connection

# GET /api/v1/status
def show
render json: {
status: 'ok',
service: 'Product Management Service',
version: 'v1',
timestamp: Time.now.utc,
environment: Rails.env,
base_url: "#{request.base_url}/api/v1",
database_status:,
uptime:
}, status: :ok
end

private

def database_status
ActiveRecord::Base.connection.active? ? 'connected' : 'disconnected'
end

def uptime
`uptime -p`.strip
end

def ensure_database_connection
return if ActiveRecord::Base.connection.active?

ActiveRecord::Base.establish_connection
Rails.logger.info 'Connected to the database'
ActiveRecord::Base.connection.execute('SELECT 1')
end
end
end
end
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
get '/', to: 'root#index'
get 'status', to: 'status#show'
resources :products, only: %i[index show create update destroy] do
member do
post :images, to: 'products#upload_images', as: :upload_images
Expand All @@ -29,5 +31,6 @@
# app is live.
get 'up' => 'rails/health#show', as: :rails_health_check

root to: redirect('/api/v1')
match '*unmatched', to: 'application#invalid_route', via: :all
end
51 changes: 51 additions & 0 deletions spec/requests/api/v1/root_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe "Api::V1::Roots", type: :request do
describe "GET /index" do
it "returns a welcome message and a list of available endpoints" do
get '/api/v1'
expect(response).to have_http_status(:ok)
expect(response.body).to include(
'Welcome to the Product Management Service API'
)
expect(response.body).to include('v1')
expect(response.body).to include(
'https://documenter.getpostman.com/view/14404907/2sAXjRWpnZ'
)
expect(response.body).to include('/api/v1/products')
expect(response.body).to include('/api/v1/categories')
expect(response.body).to include('/api/v1/cart')
expect(response.body).to include('/api/v1/orders')
expect(response.body).to include('/api/v1/status')
end

it 'has the correct base_url' do
get '/api/v1'
expect(response).to have_http_status(:ok)
expect(response_body[:base_url]).to eq('http://www.example.com/api/v1')
end

it 'returns the correct version' do
get '/api/v1'
expect(response).to have_http_status(:ok)
expect(response_body[:version]).to eq('v1')
end

it 'returns the correct documentation link' do
get '/api/v1'
expect(response).to have_http_status(:ok)
expect(response_body[:documentation]).to eq(
'https://documenter.getpostman.com/view/14404907/2sAXjRWpnZ'
)
end
end

context 'when the root endpoint is accessed' do
it 'redirects to /api/v1' do
get '/'
expect(response).to redirect_to('/api/v1')
end
end
end
66 changes: 66 additions & 0 deletions spec/requests/api/v1/status_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe "Api::V1::Status", type: :request do
describe "GET /show" do
it "returns the status of the API" do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response.body).to include('ok')
expect(response.body).to include('Product Management Service')
expect(response.body).to include('v1')
expect(response.body).to include('http://www.example.com/api/v1')
expect(response.body).to include('connected')
expect(response.body).to include('uptime')
end

it 'returns the correct environment' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:environment]).to eq('test')
end

it 'returns the correct timestamp' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:timestamp]).to be_present
end

it 'returns the correct database status' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:database_status]).to eq('connected')
end

it 'returns the correct uptime' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:uptime]).to be_present
end

it 'returns the correct base_url' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:base_url]).to eq('http://www.example.com/api/v1')
end

it 'returns the correct version' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:version]).to eq('v1')
end

it 'returns the correct service' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:service]).to eq('Product Management Service')
end

it 'returns the correct status' do
get '/api/v1/status'
expect(response).to have_http_status(:ok)
expect(response_body[:status]).to eq('ok')
end
end
end