Skip to content

Commit c766f96

Browse files
author
Juraj Chlebec
committed
Create basic Book API with search by ISBN and POST new book.
1 parent 12c041d commit c766f96

11 files changed

+175
-3
lines changed

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ gem 'jbuilder', '~> 2.5'
2626
group :development, :test do
2727
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
2828
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
29+
gem 'pry-rails'
2930
end
3031

3132
group :development do
@@ -37,3 +38,5 @@ end
3738

3839
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
3940
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
41+
42+
gem 'roar'

Gemfile.lock

+17
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@ GEM
4141
arel (8.0.0)
4242
builder (3.2.3)
4343
byebug (9.1.0)
44+
coderay (1.1.2)
4445
concurrent-ruby (1.0.5)
4546
crass (1.0.2)
47+
declarative (0.0.10)
48+
declarative-option (0.1.0)
4649
erubi (1.7.0)
4750
ffi (1.9.18)
4851
globalid (0.4.0)
@@ -72,6 +75,11 @@ GEM
7275
nokogiri (1.8.1)
7376
mini_portile2 (~> 2.3.0)
7477
pg (0.21.0)
78+
pry (0.11.1)
79+
coderay (~> 1.1.0)
80+
method_source (~> 0.9.0)
81+
pry-rails (0.3.6)
82+
pry (>= 0.10.4)
7583
puma (3.10.0)
7684
rack (2.0.3)
7785
rack-test (0.7.0)
@@ -103,6 +111,12 @@ GEM
103111
rb-fsevent (0.10.2)
104112
rb-inotify (0.9.10)
105113
ffi (>= 0.5.0, < 2)
114+
representable (3.0.4)
115+
declarative (< 0.1.0)
116+
declarative-option (< 0.2.0)
117+
uber (< 0.2.0)
118+
roar (1.1.0)
119+
representable (~> 3.0.0)
106120
ruby_dep (1.5.0)
107121
spring (2.0.2)
108122
activesupport (>= 4.2)
@@ -120,6 +134,7 @@ GEM
120134
thread_safe (0.3.6)
121135
tzinfo (1.2.3)
122136
thread_safe (~> 0.1)
137+
uber (0.1.0)
123138
websocket-driver (0.6.5)
124139
websocket-extensions (>= 0.1.0)
125140
websocket-extensions (0.1.2)
@@ -132,8 +147,10 @@ DEPENDENCIES
132147
jbuilder (~> 2.5)
133148
listen (>= 3.0.5, < 3.2)
134149
pg (~> 0.18)
150+
pry-rails
135151
puma (~> 3.7)
136152
rails (~> 5.1.4)
153+
roar
137154
spring
138155
spring-watcher-listen (~> 2.0.0)
139156
tzinfo-data
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Api::V1
2+
class ApiController < ApplicationController
3+
# Generic API stuff here
4+
end
5+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module Api::V1
2+
module Books
3+
class CrudController < ApiController
4+
5+
# POST /book-add(.:format) api/v1/books/crud#create
6+
def create
7+
book = Book.new
8+
BookRepresenter.new(book).from_json(request.body.string)
9+
book.save!
10+
11+
render status: 200, json: {
12+
status: 200,
13+
message: "Book saved!"
14+
}
15+
rescue ActiveRecord::RecordInvalid => e
16+
render status: 422, json: {
17+
status: 422,
18+
message: "Invalid request! #{e.message}"
19+
}
20+
end
21+
22+
# POST /book-add(.:format) api/v1/books/crud#create
23+
def create
24+
book = Book.new
25+
BookRepresenter.new(book).from_json(request.body.string)
26+
book.save!
27+
28+
render status: 200, json: {
29+
status: 200,
30+
message: "Book saved!"
31+
}
32+
rescue ActiveRecord::RecordInvalid => e
33+
render status: 422, json: {
34+
status: 422,
35+
message: "Invalid request! #{e.message}"
36+
}
37+
end
38+
39+
# GET /:id(.:format) api/v1/books/crud#read
40+
def read
41+
book = Book.find_by(id: params[:id])
42+
43+
if book.nil?
44+
render status: 404, json: {
45+
status: 404,
46+
message: 'Book not found!'
47+
}
48+
else
49+
render json: BookRepresenter.new(book).to_json
50+
end
51+
end
52+
53+
end
54+
end
55+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module Api::V1
2+
module Books
3+
class SearchController < ApiController
4+
5+
# GET /search/isbn/:isbn(.:format) api/v1/books/search#isbn
6+
def isbn
7+
book = Book.find_by(isbn: params[:isbn])
8+
9+
if book.nil?
10+
render status: 404, json: {
11+
status: 404,
12+
message: 'Book not found!'
13+
}
14+
else
15+
render json: BookRepresenter.new(book).to_json
16+
end
17+
end
18+
19+
end
20+
end
21+
end

app/jobs/application_job.rb

-2
This file was deleted.

app/models/book.rb

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Book < ApplicationRecord
2+
validates :title, presence: true
3+
validates :author, presence: true
4+
validates :isbn, presence: true, uniqueness: true
5+
end

app/representers/book_representer.rb

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require 'roar/decorator'
2+
require 'roar/json/hal'
3+
4+
class BookRepresenter < Roar::Decorator
5+
include Roar::JSON::HAL
6+
include Roar::Hypermedia
7+
8+
property :id
9+
property :title
10+
property :author
11+
property :isbn
12+
13+
link :self do
14+
"http://books/#{represented.id}"
15+
end
16+
end

config/routes.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
Rails.application.routes.draw do
2-
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
2+
scope module: 'api' do
3+
scope module: 'v1' do
4+
5+
# Search books API
6+
scope 'search'do
7+
get 'isbn/:isbn', to: 'books/search#isbn'
8+
end
9+
10+
post 'book-add', to: 'books/crud#create'
11+
get ':id', to: 'books/crud#read', constraints: { id: /[0-9]+/ }
12+
13+
end
14+
end
315
end
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class CreateBooks < ActiveRecord::Migration[5.1]
2+
def change
3+
create_table :books do |t|
4+
t.string :author, null: false, index: true
5+
t.string :title, null: false, index: true
6+
t.string :isbn, null: false, index: true, unique: true
7+
8+
t.timestamps null: false
9+
end
10+
end
11+
end

db/schema.rb

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This file is auto-generated from the current state of the database. Instead
2+
# of editing this file, please use the migrations feature of Active Record to
3+
# incrementally modify your database, and then regenerate this schema definition.
4+
#
5+
# Note that this schema.rb definition is the authoritative source for your
6+
# database schema. If you need to create the application database on another
7+
# system, you should be using db:schema:load, not running all the migrations
8+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
9+
# you'll amass, the slower it'll run and the greater likelihood for issues).
10+
#
11+
# It's strongly recommended that you check this file into your version control system.
12+
13+
ActiveRecord::Schema.define(version: 20171016111510) do
14+
15+
# These are extensions that must be enabled in order to support this database
16+
enable_extension "plpgsql"
17+
18+
create_table "books", force: :cascade do |t|
19+
t.string "author", null: false
20+
t.string "title", null: false
21+
t.string "isbn", null: false
22+
t.datetime "created_at", null: false
23+
t.datetime "updated_at", null: false
24+
t.index ["author"], name: "index_books_on_author"
25+
t.index ["isbn"], name: "index_books_on_isbn"
26+
t.index ["title"], name: "index_books_on_title"
27+
end
28+
29+
end

0 commit comments

Comments
 (0)