Skip to content

Commit 91a109d

Browse files
authored
[WIP] REST API (#41)
REST API Initial version
1 parent e45a1ff commit 91a109d

15 files changed

+225
-7
lines changed

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ gem "searchkick"
4242
gem "puma"
4343
gem "sendgrid-actionmailer"
4444

45+
gem "fast_jsonapi"
46+
gem "sidekiq"
47+
4548
group :production do
4649
gem "therubyracer", platforms: :ruby
4750
end

Gemfile.lock

+15-5
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ GEM
9999
execjs
100100
coffee-script-source (1.12.2)
101101
concurrent-ruby (1.0.5)
102+
connection_pool (2.2.2)
102103
crass (1.0.4)
103104
database_cleaner (1.7.0)
104105
devise (4.5.0)
@@ -126,6 +127,8 @@ GEM
126127
railties (>= 3.0.0)
127128
faraday (0.15.3)
128129
multipart-post (>= 1.2, < 3)
130+
fast_jsonapi (1.4)
131+
activesupport (>= 4.2)
129132
ffi (1.9.25)
130133
globalid (0.4.1)
131134
activesupport (>= 4.2.0)
@@ -147,7 +150,7 @@ GEM
147150
ruby_parser (~> 3.5)
148151
i18n (1.1.1)
149152
concurrent-ruby (~> 1.0)
150-
jaro_winkler (1.5.1)
153+
jaro_winkler (1.5.2)
151154
jbuilder (2.7.0)
152155
activesupport (>= 4.2.0)
153156
multi_json (>= 1.2)
@@ -208,8 +211,8 @@ GEM
208211
mime-types
209212
mimemagic (~> 0.3.0)
210213
terrapin (~> 0.6.0)
211-
parallel (1.12.1)
212-
parser (2.5.3.0)
214+
parallel (1.13.0)
215+
parser (2.6.0.0)
213216
ast (~> 2.4.0)
214217
poltergeist (1.18.1)
215218
capybara (>= 2.1, < 4)
@@ -262,6 +265,7 @@ GEM
262265
rb-fsevent (0.10.3)
263266
rb-inotify (0.9.10)
264267
ffi (>= 0.5.0, < 2)
268+
redis (4.0.2)
265269
ref (2.0.0)
266270
responders (2.4.0)
267271
actionpack (>= 4.2.0, < 5.3)
@@ -287,7 +291,7 @@ GEM
287291
rspec-mocks (~> 3.8.0)
288292
rspec-support (~> 3.8.0)
289293
rspec-support (3.8.0)
290-
rubocop (0.60.0)
294+
rubocop (0.63.1)
291295
jaro_winkler (~> 1.5.1)
292296
parallel (~> 1.10)
293297
parser (>= 2.5, != 2.5.1.1)
@@ -335,6 +339,10 @@ GEM
335339
rails (>= 3.2)
336340
shoulda-matchers (3.1.2)
337341
activesupport (>= 4.0.0)
342+
sidekiq (5.2.2)
343+
connection_pool (~> 2.2, >= 2.2.2)
344+
rack-protection (>= 1.5.0)
345+
redis (>= 3.3.5, < 5)
338346
simple_form (4.0.1)
339347
actionpack (>= 5.0)
340348
activemodel (>= 5.0)
@@ -374,7 +382,7 @@ GEM
374382
thread_safe (~> 0.1)
375383
uglifier (4.1.19)
376384
execjs (>= 0.3.0, < 3)
377-
unicode-display_width (1.4.0)
385+
unicode-display_width (1.4.1)
378386
warden (1.2.7)
379387
rack (>= 1.0)
380388
web-console (3.7.0)
@@ -408,6 +416,7 @@ DEPENDENCIES
408416
database_cleaner
409417
devise
410418
factory_bot_rails
419+
fast_jsonapi
411420
haml
412421
haml-rails
413422
jbuilder
@@ -439,6 +448,7 @@ DEPENDENCIES
439448
sendgrid-actionmailer
440449
sextant
441450
shoulda-matchers
451+
sidekiq
442452
simple_form
443453
spring
444454
spring-watcher-listen (~> 2.0.0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::AuthorsController < ApiBaseController
4+
before_action :set_author, only: :show
5+
before_action :parse_json_api_params
6+
7+
def show
8+
render json: AuthorSerializer.new(@author)
9+
end
10+
11+
def index
12+
render json: AuthorSerializer.new(
13+
Author.paginate(page: @query.page_number, per_page: @query.per_page)
14+
)
15+
end
16+
17+
private
18+
19+
def set_author
20+
@author = Author.find_by!(grandham_id: params[:id])
21+
end
22+
end
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::BooksController < ApiBaseController
4+
before_action :set_book, only: :show
5+
before_action :parse_json_api_params
6+
7+
def show
8+
render json: BookSerializer.new(@book)
9+
end
10+
11+
def index
12+
@books = if @query.search_query.present?
13+
Book
14+
.includes(:authors, :libraries)
15+
.search(@query.search_query, page: @query.page_number, per_page: @query.per_page)
16+
else
17+
Book
18+
.includes(:authors, :libraries)
19+
.paginate(page: @query.page_number, per_page: @query.per_page)
20+
end
21+
render json: BookSerializer.new(@books, include: %i[authors libraries])
22+
end
23+
24+
private
25+
26+
def set_book
27+
@book = Book.find_by!(grandham_id: params[:id])
28+
end
29+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::LibrariesController < ApiBaseController
4+
before_action :set_library, only: :show
5+
before_action :parse_json_api_params
6+
7+
def show
8+
render json: LibrarySerializer.new(@library)
9+
end
10+
11+
def index
12+
@libraries = if @query.search_query.present?
13+
Library.search(@query.search_query, page: @query.page_number, per_page: @query.per_page)
14+
else
15+
Library.paginate(page: @query.page_number, per_page: @query.per_page)
16+
end
17+
18+
render json: LibrarySerializer.new(@libraries)
19+
end
20+
21+
private
22+
23+
def set_library
24+
@ibrary = Library.find_by!(grandham_id: params[:id])
25+
end
26+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::PublishersController < ApiBaseController
4+
before_action :set_publisher, only: :show
5+
before_action :parse_json_api_params
6+
7+
def show
8+
render json: PublisherSerializer.new(@publisher)
9+
end
10+
11+
def index
12+
@publishers = if @query.search_query.present?
13+
Publisher.search(@query.search_query, page: @query.page_number, per_page: @query.per_page)
14+
else
15+
Publisher.paginate(page: @query.page_number, per_page: @query.per_page)
16+
end
17+
18+
render json: PublisherSerializer.new(@publishers)
19+
end
20+
21+
private
22+
23+
def set_publisher
24+
@publisher = Publisher.find_by!(grandham_id: params[:id])
25+
end
26+
end
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
class ApiBaseController < ApplicationController
4+
rescue_from ActiveRecord::RecordNotFound do |_exception|
5+
head :not_found
6+
end
7+
8+
protected
9+
10+
def parse_json_api_params
11+
@query = JsonApiQueryParser.new(params)
12+
@query.call
13+
end
14+
end

app/controllers/searches_controller.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def resource(action)
2424
end
2525

2626
def get_results
27-
@results = Search.new(resource(params[:action]), params[:query], params[:page]).results if params[:query].present?
27+
search_query = MalayalamTextNormalizer.new(params[:query]).call
28+
@results = Search.new(resource(params[:action]), search_query, params[:page]).results if params[:query].present?
2829
end
2930
end

app/serializers/author_serializer.rb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class AuthorSerializer
4+
include FastJsonapi::ObjectSerializer
5+
attributes :name, :language
6+
set_id :grandham_id
7+
end

app/serializers/book_serializer.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
class BookSerializer
4+
include FastJsonapi::ObjectSerializer
5+
set_id :grandham_id
6+
attributes :grandham_id, :title, :isbn, :pages, :year, :description, :edition, :ddc, :volume,
7+
:series, :price, :length, :title_orginal, :illustrator, :note, :preface
8+
9+
has_many :authors
10+
has_many :libraries
11+
end

app/serializers/library_serializer.rb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class LibrarySerializer
4+
include FastJsonapi::ObjectSerializer
5+
set_id :grandham_id
6+
attributes :name, :place, :language
7+
end
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class PublisherSerializer
4+
include FastJsonapi::ObjectSerializer
5+
set_id :grandham_id
6+
attributes :name, :place, :language
7+
end

app/services/json_api_query_parser.rb

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
class JsonApiQueryParser
4+
attr_reader :page_number, :per_page, :search_query
5+
def initialize(params, options = nil)
6+
@params = params.is_a?(Hash) ? params : params.permit(:query, page: %i[number size]).to_h
7+
@options = options
8+
end
9+
10+
def call
11+
@page_number = params.dig("page", "number") || 1
12+
@per_page = params.dig("page", "size") || 20
13+
@search_query = MalayalamTextNormalizer.new(params["query"]).call
14+
end
15+
16+
private
17+
18+
attr_reader :params, :options
19+
end
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
class MalayalamTextNormalizer
4+
ATOMIC_CHILLU_MAP = {
5+
"ന്‍" => "ൻ",
6+
"ണ്‍" => "ൺ",
7+
"ര്‍" => "ർ",
8+
"ല്‍" => "ൽ",
9+
"ള്‍" => "ൾ",
10+
"ക്‍" => "ൿ"
11+
}.freeze
12+
def initialize(text)
13+
@text = text
14+
end
15+
16+
def call
17+
return text if text.blank?
18+
19+
ATOMIC_CHILLU_MAP.each do |non_atomic, atomic|
20+
@text = text.gsub(atomic, non_atomic)
21+
end
22+
text
23+
end
24+
25+
private
26+
27+
attr_reader :text
28+
end

config/routes.rb

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
Grandham::Application.routes.draw do
3+
Grandham::Application.routes.draw do # rubocop:disable Metrics/BlockLength
44
get "qr_generator/image"
55

66
get "error/access_denied"
@@ -71,4 +71,12 @@
7171
get :books, on: :member
7272
end
7373
end
74+
namespace :api do
75+
namespace :v1 do
76+
resources :books, only: %i[show index]
77+
resources :authors, only: %i[show index]
78+
resources :libraries, only: %i[show index]
79+
resources :publishers, only: %i[show index]
80+
end
81+
end
7482
end

0 commit comments

Comments
 (0)