├── .gitignore ├── .overcommit.yml ├── .rspec ├── .rubocop.yml ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── api │ │ └── v1 │ │ │ ├── authors_controller.rb │ │ │ └── books_controller.rb │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ └── graphql_controller.rb ├── graphql │ ├── mutations │ │ ├── author_mutations │ │ │ ├── create_author.rb │ │ │ ├── destroy_author.rb │ │ │ └── update_author.rb │ │ ├── base_mutation.rb │ │ └── book_mutations │ │ │ ├── create_book.rb │ │ │ ├── destroy_book.rb │ │ │ └── update_book.rb │ ├── rest_graphql_schema.rb │ └── types │ │ ├── .keep │ │ ├── author_type.rb │ │ ├── base_enum.rb │ │ ├── base_input_object.rb │ │ ├── base_interface.rb │ │ ├── base_object.rb │ │ ├── base_scalar.rb │ │ ├── base_union.rb │ │ ├── book_type.rb │ │ ├── mutation_type.rb │ │ └── query_type.rb ├── jobs │ └── application_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── application_record.rb │ ├── author.rb │ ├── authorship.rb │ ├── book.rb │ └── concerns │ │ └── .keep ├── serializers │ ├── author_serializer.rb │ └── book_serializer.rb └── views │ └── layouts │ ├── mailer.html.erb │ └── mailer.text.erb ├── bin ├── bundle ├── rails ├── rake ├── setup ├── spring └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── credentials.yml.enc ├── database.yml.example ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── backtrace_silencers.rb │ ├── cors.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── puma.rb ├── routes.rb ├── spring.rb └── storage.yml ├── db ├── migrate │ ├── 20181203105241_create_books.rb │ ├── 20181203105334_create_authors.rb │ └── 20181203120508_create_authorships.rb ├── schema.rb └── seeds.rb ├── lib └── tasks │ └── .keep ├── public ├── images │ ├── result1.png │ ├── result2.png │ ├── result3.png │ ├── result4.png │ └── result5.png └── robots.txt ├── spec ├── models │ ├── author_spec.rb │ └── book_spec.rb └── spec_helper.rb └── vendor └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle 2 | # Ignore all logfiles and tempfiles. 3 | .idea/* 4 | /log/* 5 | /tmp/* 6 | # Ignore uploaded files in development 7 | /storage/* 8 | # Ignore master key for decrypting credentials and more. 9 | /config/master.key 10 | /node_modules 11 | /yarn-error.log 12 | .byebug_history 13 | .ruby-version 14 | .ruby-gemset 15 | config/database.yml 16 | coverage/ 17 | public/system/* 18 | public/uploads/* 19 | .env 20 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | PreCommit: 2 | ALL: 3 | problem_on_unmodified_line: ignore 4 | required: false 5 | quiet: false 6 | RuboCop: 7 | enabled: true 8 | on_warn: fail # Treat all warnings as failures 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'db/**/*' 4 | - 'bin/*' 5 | - 'config/**/*' 6 | - 'public/**/*' 7 | - 'spec/**/*' 8 | - 'test/**/*' 9 | - 'vendor/**/*' 10 | - 'spec/fixtures/**/*' 11 | - 'tmp/**/*' 12 | 13 | Style/FrozenStringLiteralComment: 14 | Enabled: false 15 | 16 | Style/Documentation: 17 | Enabled: false 18 | 19 | Layout/EmptyLinesAroundModuleBody: 20 | EnforcedStyle: empty_lines 21 | 22 | Layout/EmptyLinesAroundClassBody: 23 | EnforcedStyle: empty_lines 24 | 25 | Metrics/LineLength: 26 | Max: 120 27 | 28 | Metrics/ClassLength: 29 | Max: 250 30 | 31 | Metrics/ModuleLength: 32 | Max: 250 33 | 34 | Metrics/AbcSize: 35 | Max: 25 36 | 37 | Metrics/MethodLength: 38 | Max: 20 39 | 40 | Metrics/CyclomaticComplexity: 41 | Max: 7 42 | 43 | Rails: 44 | Enabled: true 45 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | ruby '2.5.1' 5 | 6 | gem 'active_model_serializers' 7 | gem 'graphql' 8 | gem 'graphql-preload', '~> 2.0.1' 9 | gem 'rails', '~> 5.2.1', '>= 5.2.1.1' 10 | gem 'pg', '>= 0.18', '< 2.0' 11 | gem 'puma', '~> 3.11' 12 | gem 'bootsnap', '>= 1.1.0', require: false 13 | gem 'search_object' 14 | gem 'search_object_graphql' 15 | 16 | group :development, :test do 17 | gem 'faker' 18 | gem 'byebug', platforms: %i[mri mingw x64_mingw] 19 | end 20 | 21 | group :development do 22 | gem 'graphiql-rails' 23 | gem 'listen', '>= 3.0.5', '< 3.2' 24 | gem 'spring' 25 | gem 'spring-watcher-listen', '~> 2.0.0' 26 | end 27 | 28 | gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] 29 | 30 | gem 'fast_jsonapi' 31 | gem 'rack-cors', require: 'rack/cors' 32 | group :development do 33 | gem 'annotate' 34 | gem 'overcommit' 35 | gem 'rubocop', require: false 36 | end 37 | 38 | group :development, :test do 39 | gem 'rspec-rails' 40 | end 41 | 42 | group :test do 43 | gem 'database_cleaner' 44 | gem 'factory_bot_rails' 45 | gem 'shoulda-matchers' 46 | gem 'simplecov', require: false 47 | end 48 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (5.2.2) 5 | actionpack (= 5.2.2) 6 | nio4r (~> 2.0) 7 | websocket-driver (>= 0.6.1) 8 | actionmailer (5.2.2) 9 | actionpack (= 5.2.2) 10 | actionview (= 5.2.2) 11 | activejob (= 5.2.2) 12 | mail (~> 2.5, >= 2.5.4) 13 | rails-dom-testing (~> 2.0) 14 | actionpack (5.2.2) 15 | actionview (= 5.2.2) 16 | activesupport (= 5.2.2) 17 | rack (~> 2.0) 18 | rack-test (>= 0.6.3) 19 | rails-dom-testing (~> 2.0) 20 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 21 | actionview (5.2.2) 22 | activesupport (= 5.2.2) 23 | builder (~> 3.1) 24 | erubi (~> 1.4) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 27 | active_model_serializers (0.10.8) 28 | actionpack (>= 4.1, < 6) 29 | activemodel (>= 4.1, < 6) 30 | case_transform (>= 0.2) 31 | jsonapi-renderer (>= 0.1.1.beta1, < 0.3) 32 | activejob (5.2.2) 33 | activesupport (= 5.2.2) 34 | globalid (>= 0.3.6) 35 | activemodel (5.2.2) 36 | activesupport (= 5.2.2) 37 | activerecord (5.2.2) 38 | activemodel (= 5.2.2) 39 | activesupport (= 5.2.2) 40 | arel (>= 9.0) 41 | activestorage (5.2.2) 42 | actionpack (= 5.2.2) 43 | activerecord (= 5.2.2) 44 | marcel (~> 0.3.1) 45 | activesupport (5.2.2) 46 | concurrent-ruby (~> 1.0, >= 1.0.2) 47 | i18n (>= 0.7, < 2) 48 | minitest (~> 5.1) 49 | tzinfo (~> 1.1) 50 | annotate (2.7.4) 51 | activerecord (>= 3.2, < 6.0) 52 | rake (>= 10.4, < 13.0) 53 | arel (9.0.0) 54 | ast (2.4.0) 55 | bootsnap (1.3.2) 56 | msgpack (~> 1.0) 57 | builder (3.2.3) 58 | byebug (10.0.2) 59 | case_transform (0.2) 60 | activesupport 61 | childprocess (0.9.0) 62 | ffi (~> 1.0, >= 1.0.11) 63 | concurrent-ruby (1.1.3) 64 | crass (1.0.4) 65 | database_cleaner (1.7.0) 66 | diff-lcs (1.3) 67 | docile (1.3.1) 68 | erubi (1.7.1) 69 | factory_bot (4.11.1) 70 | activesupport (>= 3.0.0) 71 | factory_bot_rails (4.11.1) 72 | factory_bot (~> 4.11.1) 73 | railties (>= 3.0.0) 74 | faker (1.9.1) 75 | i18n (>= 0.7) 76 | fast_jsonapi (1.5) 77 | activesupport (>= 4.2) 78 | ffi (1.9.25) 79 | globalid (0.4.1) 80 | activesupport (>= 4.2.0) 81 | graphiql-rails (1.5.0) 82 | railties 83 | sprockets-rails 84 | graphql (1.8.11) 85 | graphql-batch (0.3.10) 86 | graphql (>= 0.8, < 2) 87 | promise.rb (~> 0.7.2) 88 | graphql-preload (2.0.1) 89 | activerecord (>= 4.1, < 6) 90 | graphql (>= 1.5, < 2) 91 | graphql-batch (~> 0.3) 92 | promise.rb (~> 0.7) 93 | i18n (1.1.1) 94 | concurrent-ruby (~> 1.0) 95 | iniparse (1.4.4) 96 | jaro_winkler (1.5.1) 97 | json (2.1.0) 98 | jsonapi-renderer (0.2.0) 99 | listen (3.1.5) 100 | rb-fsevent (~> 0.9, >= 0.9.4) 101 | rb-inotify (~> 0.9, >= 0.9.7) 102 | ruby_dep (~> 1.2) 103 | loofah (2.2.3) 104 | crass (~> 1.0.2) 105 | nokogiri (>= 1.5.9) 106 | mail (2.7.1) 107 | mini_mime (>= 0.1.1) 108 | marcel (0.3.3) 109 | mimemagic (~> 0.3.2) 110 | method_source (0.9.2) 111 | mimemagic (0.3.2) 112 | mini_mime (1.0.1) 113 | mini_portile2 (2.3.0) 114 | minitest (5.11.3) 115 | msgpack (1.2.4) 116 | nio4r (2.3.1) 117 | nokogiri (1.8.5) 118 | mini_portile2 (~> 2.3.0) 119 | overcommit (0.46.0) 120 | childprocess (~> 0.6, >= 0.6.3) 121 | iniparse (~> 1.4) 122 | parallel (1.12.1) 123 | parser (2.5.3.0) 124 | ast (~> 2.4.0) 125 | pg (1.1.3) 126 | powerpack (0.1.2) 127 | promise.rb (0.7.4) 128 | puma (3.12.0) 129 | rack (2.0.6) 130 | rack-cors (1.0.2) 131 | rack-test (1.1.0) 132 | rack (>= 1.0, < 3) 133 | rails (5.2.2) 134 | actioncable (= 5.2.2) 135 | actionmailer (= 5.2.2) 136 | actionpack (= 5.2.2) 137 | actionview (= 5.2.2) 138 | activejob (= 5.2.2) 139 | activemodel (= 5.2.2) 140 | activerecord (= 5.2.2) 141 | activestorage (= 5.2.2) 142 | activesupport (= 5.2.2) 143 | bundler (>= 1.3.0) 144 | railties (= 5.2.2) 145 | sprockets-rails (>= 2.0.0) 146 | rails-dom-testing (2.0.3) 147 | activesupport (>= 4.2.0) 148 | nokogiri (>= 1.6) 149 | rails-html-sanitizer (1.0.4) 150 | loofah (~> 2.2, >= 2.2.2) 151 | railties (5.2.2) 152 | actionpack (= 5.2.2) 153 | activesupport (= 5.2.2) 154 | method_source 155 | rake (>= 0.8.7) 156 | thor (>= 0.19.0, < 2.0) 157 | rainbow (3.0.0) 158 | rake (12.3.2) 159 | rb-fsevent (0.10.3) 160 | rb-inotify (0.9.10) 161 | ffi (>= 0.5.0, < 2) 162 | rspec-core (3.8.0) 163 | rspec-support (~> 3.8.0) 164 | rspec-expectations (3.8.2) 165 | diff-lcs (>= 1.2.0, < 2.0) 166 | rspec-support (~> 3.8.0) 167 | rspec-mocks (3.8.0) 168 | diff-lcs (>= 1.2.0, < 2.0) 169 | rspec-support (~> 3.8.0) 170 | rspec-rails (3.8.1) 171 | actionpack (>= 3.0) 172 | activesupport (>= 3.0) 173 | railties (>= 3.0) 174 | rspec-core (~> 3.8.0) 175 | rspec-expectations (~> 3.8.0) 176 | rspec-mocks (~> 3.8.0) 177 | rspec-support (~> 3.8.0) 178 | rspec-support (3.8.0) 179 | rubocop (0.61.1) 180 | jaro_winkler (~> 1.5.1) 181 | parallel (~> 1.10) 182 | parser (>= 2.5, != 2.5.1.1) 183 | powerpack (~> 0.1) 184 | rainbow (>= 2.2.2, < 4.0) 185 | ruby-progressbar (~> 1.7) 186 | unicode-display_width (~> 1.4.0) 187 | ruby-progressbar (1.10.0) 188 | ruby_dep (1.5.0) 189 | search_object (1.2.1) 190 | search_object_graphql (0.1) 191 | graphql (~> 1.5) 192 | search_object (~> 1.2) 193 | shoulda-matchers (3.1.2) 194 | activesupport (>= 4.0.0) 195 | simplecov (0.16.1) 196 | docile (~> 1.1) 197 | json (>= 1.8, < 3) 198 | simplecov-html (~> 0.10.0) 199 | simplecov-html (0.10.2) 200 | spring (2.0.2) 201 | activesupport (>= 4.2) 202 | spring-watcher-listen (2.0.1) 203 | listen (>= 2.7, < 4.0) 204 | spring (>= 1.2, < 3.0) 205 | sprockets (3.7.2) 206 | concurrent-ruby (~> 1.0) 207 | rack (> 1, < 3) 208 | sprockets-rails (3.2.1) 209 | actionpack (>= 4.0) 210 | activesupport (>= 4.0) 211 | sprockets (>= 3.0.0) 212 | thor (0.20.3) 213 | thread_safe (0.3.6) 214 | tzinfo (1.2.5) 215 | thread_safe (~> 0.1) 216 | unicode-display_width (1.4.0) 217 | websocket-driver (0.7.0) 218 | websocket-extensions (>= 0.1.0) 219 | websocket-extensions (0.1.3) 220 | 221 | PLATFORMS 222 | ruby 223 | 224 | DEPENDENCIES 225 | active_model_serializers 226 | annotate 227 | bootsnap (>= 1.1.0) 228 | byebug 229 | database_cleaner 230 | factory_bot_rails 231 | faker 232 | fast_jsonapi 233 | graphiql-rails 234 | graphql 235 | graphql-preload (~> 2.0.1) 236 | listen (>= 3.0.5, < 3.2) 237 | overcommit 238 | pg (>= 0.18, < 2.0) 239 | puma (~> 3.11) 240 | rack-cors 241 | rails (~> 5.2.1, >= 5.2.1.1) 242 | rspec-rails 243 | rubocop 244 | search_object 245 | search_object_graphql 246 | shoulda-matchers 247 | simplecov 248 | spring 249 | spring-watcher-listen (~> 2.0.0) 250 | tzinfo-data 251 | 252 | RUBY VERSION 253 | ruby 2.5.1p57 254 | 255 | BUNDLED WITH 256 | 1.17.1 257 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rest API vs Graphql-ruby 2 | This is the base example of using REST and GraphQL API for your rails application. 3 | 4 | This application is using the [`graphql-ruby` gem](https://github.com/rmosolgo/graphql-ruby) 5 | 6 | * [Models](#models) 7 | * [Getting all data](#getting-all-data) 8 | * [Finding a record](#finding-a-record) 9 | * [Creating a record](#createing-a-record) 10 | * [Record deleting](#record-deleting) 11 | 12 | ## Models 13 | 14 | This app has two models: `author` and `book`: 15 | 16 | `app/models/author.rb`: 17 | ```ruby 18 | class Author < ApplicationRecord 19 | 20 | validates :name, presence: true 21 | 22 | has_many :authorships, dependent: :destroy 23 | has_many :books, through: :authorships, dependent: :destroy 24 | 25 | end 26 | ``` 27 | 28 | `app/models/book.rb`: 29 | ```ruby 30 | class Book < ApplicationRecord 31 | 32 | validates :title, presence: true 33 | 34 | has_many :authorships, dependent: :nullify 35 | has_many :authors, through: :authorships 36 | 37 | end 38 | ``` 39 | ## Getting all data 40 | ### Rest API 41 | 42 | `config/routes.rb`: 43 | ```ruby 44 | namespace :api do 45 | namespace :v1 do 46 | resources :authors 47 | end 48 | end 49 | ``` 50 | 51 | `app/controllers/api/v1/authors_controller.rb`: 52 | ```ruby 53 | module Api 54 | 55 | module V1 56 | 57 | class AuthorsController < ApplicationController 58 | 59 | def index 60 | authors = Author.all 61 | render json: authors 62 | end 63 | 64 | end 65 | 66 | end 67 | 68 | end 69 | ``` 70 | `app/serializers/author_serializer.rb`: 71 | ```ruby 72 | class AuthorSerializer < ActiveModel::Serializer 73 | 74 | attributes :id, :name 75 | has_many :books, through: :authorships 76 | 77 | end 78 | ``` 79 | Rest API request: 80 | 81 | GET: `localhost:3000/api/v1/authors`: 82 | ```json 83 | [ 84 | { 85 | "id": 16, 86 | "name": "Lazaro McKenzie", 87 | "books": [ 88 | { 89 | "id": 28, 90 | "title": "A Catskill Eagle", 91 | "description": "This sounds like something The One True Morty might say." 92 | }, 93 | { 94 | "id": 32, 95 | "title": "Moab Is My Washpot", 96 | "description": "I don't get it and I don't need to." 97 | } 98 | ] 99 | }, 100 | { 101 | "id": 17, 102 | "name": "Tyrone Heller", 103 | "books": [ 104 | { 105 | "id": 21, 106 | "title": "I Sing the Body Electric", 107 | "description": "Pluto's a planet." 108 | }, 109 | { 110 | "id": 32, 111 | "title": "Moab Is My Washpot", 112 | "description": "I don't get it and I don't need to." 113 | } 114 | ] 115 | }, 116 | { 117 | "id": 18, 118 | "name": "Shiela Williamson", 119 | "books": [ 120 | { 121 | "id": 25, 122 | "title": "No Highway", 123 | "description": "I want that Mulan McNugget sauce, Morty!" 124 | } 125 | ] 126 | } 127 | ] 128 | ``` 129 | ### Graphql 130 | Unlike the REST API GraphQL has only one endpoint: 131 | 132 | `config/routes.rb`: 133 | ```ruby 134 | post "/graphql", to: "graphql#execute" 135 | ``` 136 | 137 | `app/graphql/types/query_type.rb`: 138 | ```ruby 139 | module Types 140 | 141 | class QueryType < Types::BaseObject 142 | 143 | field :authors, [Types::AuthorType], null: false 144 | 145 | def authors 146 | Author.all 147 | end 148 | 149 | end 150 | 151 | end 152 | ``` 153 | GraphQL request: 154 |

155 | 156 |

157 | 158 | This is how you can execute the query in Ruby: 159 | ```ruby 160 | query_string = " 161 | { 162 | authors { 163 | id 164 | name 165 | books { 166 | id 167 | title 168 | description 169 | } 170 | } 171 | } 172 | " 173 | 174 | RestGraphqlSchema.execute(query_string) 175 | ``` 176 | 177 | ## Finding a record 178 | ### Rest API 179 | `app/controllers/api/v1/authors_controller.rb`: 180 | 181 | ```ruby 182 | def show 183 | render json: Author.find(params[:id]) 184 | end 185 | ``` 186 | Rest API request: 187 | 188 | GET: `localhost:3000/api/v1/authors/16`: 189 | ```json 190 | { 191 | "id": 16, 192 | "name": "Lazaro McKenzie", 193 | "books": [ 194 | { 195 | "id": 28, 196 | "title": "A Catskill Eagle", 197 | "description": "This sounds like something The One True Morty might say." 198 | }, 199 | { 200 | "id": 32, 201 | "title": "Moab Is My Washpot", 202 | "description": "I don't get it and I don't need to." 203 | } 204 | ] 205 | } 206 | ``` 207 | ### GraphQL 208 | `app/graphql/types/query_type.rb` 209 | ```ruby 210 | field :author, Types::AuthorType, null: true do 211 | argument :id, ID, required: true 212 | end 213 | 214 | def author(id:) 215 | Author.find_by(id: id) 216 | end 217 | ``` 218 | Request: 219 |

220 | 221 |

222 | 223 | ## Creating a record 224 | ### Rest API 225 | `app/controllers/api/v1/authors_controller.rb`: 226 | ```ruby 227 | def create 228 | author = Author.new(author_params) 229 | if author.save 230 | render json: author, status: :created 231 | else 232 | render json: author.errors, status: :unprocessable_entity 233 | end 234 | end 235 | 236 | private 237 | 238 | def author_params 239 | params.require(:author).permit(:name) 240 | end 241 | ``` 242 | 243 | Rest API request: 244 | 245 | POST: `localhost:3000/api/v1/authors`: 246 | 247 | Params: `author[name]: "Robert B. Parker"` 248 | ```json 249 | { 250 | "id": 58, 251 | "name": "Robert B. Parker", 252 | "books": [] 253 | } 254 | ``` 255 | 256 | ### GraphQL 257 | `app/graphql/types/mutation_type.rb`: 258 | ```ruby 259 | module Types 260 | 261 | class MutationType < Types::BaseObject 262 | 263 | field :create_author, mutation: Mutations::AuthorMutations::CreateAuthor 264 | 265 | end 266 | 267 | end 268 | ``` 269 | `app/graphql/mutations/author_mutations/create_author.rb`: 270 | ```ruby 271 | module Mutations 272 | 273 | module AuthorMutations 274 | 275 | class CreateAuthor < Mutations::BaseMutation 276 | 277 | null true 278 | 279 | argument :name, String, required: true 280 | 281 | field :author, Types::AuthorType, null: true 282 | field :errors, [String], null: false 283 | 284 | def resolve(name:) 285 | author = Author.create(name: name) 286 | if author.present? 287 | # Successful creation, return the created object with no errors 288 | { 289 | author: author, 290 | errors: [] 291 | } 292 | else 293 | # Failed save, return the errors to the client 294 | { 295 | author: nil, 296 | errors: author.errors.full_messages 297 | } 298 | end 299 | end 300 | 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | ``` 308 | Request: 309 |

310 | 311 |

312 | 313 | ## Record deleting 314 | ### Rest API 315 | `app/controllers/api/v1/authors_controller.rb`: 316 | ```ruby 317 | def destroy 318 | @author.destroy 319 | end 320 | 321 | private 322 | 323 | def set_author 324 | @author = Author.find(params[:id]) 325 | end 326 | ``` 327 | DELETE: `localhost:3000/api/v1/authors/58`: 328 | 329 | ``` 330 | Status: 204 No Content 331 | ``` 332 | 333 | ## GraphQL 334 | `app/graphql/mutations/author_mutations/destroy_author.rb`: 335 | ```ruby 336 | field :destroy_author, mutation: Mutations::AuthorMutations::DestroyAuthor 337 | ``` 338 | `app/graphql/mutations/author_mutations/destroy_author.rb`: 339 | ```ruby 340 | module Mutations 341 | 342 | module AuthorMutations 343 | 344 | class DestroyAuthor < Mutations::BaseMutation 345 | 346 | null false 347 | 348 | argument :id, ID, 'the ID of the author to delete', required: true 349 | 350 | field :author, Types::AuthorType, null: true 351 | field :errors, [String], null: false 352 | 353 | def resolve(id:) 354 | author = Author.find_by(id: id) 355 | author&.destroy 356 | { 357 | author: author, 358 | errors: [] 359 | } 360 | end 361 | 362 | end 363 | 364 | end 365 | 366 | end 367 | ``` 368 | Request: 369 |

370 | 371 |

372 | 373 | If you try delete the same record again server will response with empty object: 374 |

375 | 376 |

377 | 378 | ## Useful links 379 | * [GraphQL or REST? What should I use?](https://dev.to/sadarshannaiynar/graphql-or-rest-what-should-i-use-38mj) 380 | * [GraphQL guide](http://graphql-ruby.org/guides) 381 | * [How to graphql tutorial](https://www.howtographql.com/graphql-ruby/1-getting-started/) 382 | 383 | ## License 384 | Timebot is Copyright © 2015-2019 Codica. It is released under the [MIT License](https://opensource.org/licenses/MIT). 385 | 386 | ## About Codica 387 | 388 | [![Codica logo](https://www.codica.com/assets/images/logo/logo.svg)](https://www.codica.com) 389 | 390 | rest-graphql is maintained and funded by Codica. The names and logos for Codica are trademarks of Codica. 391 | 392 | We love open source software! See [our other projects](https://github.com/codica2) or [hire us](https://www.codica.com/) to design, develop, and grow your product. 393 | 394 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | 3 | class Channel < ActionCable::Channel::Base 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | 3 | class Connection < ActionCable::Connection::Base 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/controllers/api/v1/authors_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | 5 | module V1 6 | 7 | class AuthorsController < ApplicationController 8 | 9 | before_action :set_author, only: %i[show update destroy] 10 | 11 | def index 12 | authors = Author.all 13 | render json: authors 14 | end 15 | 16 | def show 17 | render json: @author 18 | end 19 | 20 | def create 21 | author = Author.new(author_params) 22 | if author.save 23 | render json: author, status: :created 24 | else 25 | render json: author.errors, status: :unprocessable_entity 26 | end 27 | end 28 | 29 | def update 30 | if @author.update(author_params) 31 | render json: @author, status: :ok 32 | else 33 | render json: @author.errors, status: :unprocessable_entity 34 | end 35 | end 36 | 37 | def destroy 38 | @author.destroy 39 | end 40 | 41 | private 42 | 43 | def set_author 44 | @author = Author.find(params[:id]) 45 | end 46 | 47 | def author_params 48 | params.require(:author).permit(:name) 49 | end 50 | 51 | end 52 | 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /app/controllers/api/v1/books_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | 5 | module V1 6 | 7 | class BooksController < ApplicationController 8 | 9 | before_action :set_book, only: %i[show update destroy] 10 | 11 | def index 12 | books = Book.all 13 | render json: books 14 | end 15 | 16 | def show 17 | render json: @book 18 | end 19 | 20 | def create 21 | book = Book.new(book_params) 22 | if book.save 23 | render json: book, status: :created 24 | else 25 | render json: book.errors, status: :unprocessable_entity 26 | end 27 | end 28 | 29 | def update 30 | if @book.update(book_params) 31 | render json: @book, status: :ok 32 | else 33 | render json: @book.errors, status: :unprocessable_entity 34 | end 35 | end 36 | 37 | def destroy 38 | @book.destroy 39 | end 40 | 41 | private 42 | 43 | def set_book 44 | @book = Book.find(params[:id]) 45 | end 46 | 47 | def book_params 48 | params.require(:book).permit(:title, :description) 49 | end 50 | 51 | end 52 | 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::API 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/graphql_controller.rb: -------------------------------------------------------------------------------- 1 | class GraphqlController < ApplicationController 2 | 3 | def execute 4 | variables = ensure_hash(params[:variables]) 5 | query = params[:query] 6 | operation_name = params[:operationName] 7 | context = { 8 | # Query context goes here, for example: 9 | # current_user: current_user, 10 | } 11 | result = RestGraphqlSchema.execute(query, variables: variables, context: context, operation_name: operation_name) 12 | render json: result 13 | rescue StandardError => e 14 | raise e unless Rails.env.development? 15 | 16 | handle_error_in_development e 17 | end 18 | 19 | private 20 | 21 | # Handle form data, JSON body, or a blank value 22 | def ensure_hash(ambiguous_param) 23 | case ambiguous_param 24 | when String 25 | if ambiguous_param.present? 26 | ensure_hash(JSON.parse(ambiguous_param)) 27 | else 28 | {} 29 | end 30 | when Hash, ActionController::Parameters 31 | ambiguous_param 32 | when nil 33 | {} 34 | else 35 | raise ArgumentError, "Unexpected parameter: #{ambiguous_param}" 36 | end 37 | end 38 | 39 | def handle_error_in_development(error) 40 | logger.error error.message 41 | logger.error error.backtrace.join("\n") 42 | 43 | render json: { 44 | error: { 45 | message: error.message, 46 | backtrace: error.backtrace 47 | }, data: {} 48 | }, status: :internal_server_error 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /app/graphql/mutations/author_mutations/create_author.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module AuthorMutations 4 | 5 | class CreateAuthor < Mutations::BaseMutation 6 | 7 | null true 8 | 9 | argument :name, String, required: true 10 | 11 | field :author, Types::AuthorType, null: true 12 | field :errors, [String], null: false 13 | 14 | def resolve(name:) 15 | author = Author.create(name: name) 16 | if author.present? 17 | # Successful creation, return the created object with no errors 18 | { 19 | author: author, 20 | errors: [] 21 | } 22 | else 23 | # Failed save, return the errors to the client 24 | { 25 | author: nil, 26 | errors: author.errors.full_messages 27 | } 28 | end 29 | end 30 | 31 | end 32 | 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /app/graphql/mutations/author_mutations/destroy_author.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module AuthorMutations 4 | 5 | class DestroyAuthor < Mutations::BaseMutation 6 | 7 | null false 8 | 9 | argument :id, ID, 'the ID of the author to delete', required: true 10 | 11 | field :author, Types::AuthorType, null: true 12 | field :errors, [String], null: false 13 | 14 | def resolve(id:) 15 | author = Author.find_by(id: id) 16 | author&.destroy 17 | { 18 | author: author, 19 | errors: [] 20 | } 21 | end 22 | 23 | end 24 | 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /app/graphql/mutations/author_mutations/update_author.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module AuthorMutations 4 | 5 | class UpdateAuthor < Mutations::BaseMutation 6 | 7 | null false 8 | 9 | argument :id, ID, 'the ID of the author to edit', required: true 10 | argument :name, String, 'the new name', required: true 11 | 12 | field :author, Types::AuthorType, null: true 13 | field :errors, [String], null: false 14 | 15 | def resolve(id:, name:) 16 | author = Author.find_by(id: id) 17 | if author&.update(name: name) 18 | { 19 | author: author, 20 | errors: [] 21 | } 22 | else 23 | { 24 | author: nil, 25 | errors: author.errors.full_messages 26 | } 27 | end 28 | end 29 | 30 | end 31 | 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /app/graphql/mutations/base_mutation.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | class BaseMutation < GraphQL::Schema::RelayClassicMutation 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/mutations/book_mutations/create_book.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module BookMutations 4 | 5 | class CreateBook < Mutations::BaseMutation 6 | 7 | null false 8 | 9 | argument :title, String, required: true 10 | argument :description, String, required: false 11 | 12 | field :book, Types::BookType, null: true 13 | field :errors, [String], null: false 14 | 15 | def resolve(title:, description:) 16 | book = Book.create(title: title, description: description) 17 | if book.present? 18 | # Successful creation, return the created object with no errors 19 | { 20 | book: book, 21 | errors: [] 22 | } 23 | else 24 | # Failed save, return the errors to the client 25 | { 26 | book: nil, 27 | errors: book.errors.full_messages 28 | } 29 | end 30 | end 31 | 32 | end 33 | 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /app/graphql/mutations/book_mutations/destroy_book.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module BookMutations 4 | 5 | class DestroyBook < Mutations::BaseMutation 6 | 7 | null false 8 | 9 | argument :id, ID, 'the ID of the book to delete', required: true 10 | 11 | field :book, Types::BookType, null: true 12 | field :errors, [String], null: false 13 | 14 | def resolve(id) 15 | book = Book.find_by(id: id)&.destroy 16 | { 17 | book: book, 18 | errors: [] 19 | } 20 | end 21 | 22 | end 23 | 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /app/graphql/mutations/book_mutations/update_book.rb: -------------------------------------------------------------------------------- 1 | module Mutations 2 | 3 | module BookMutations 4 | 5 | class UpdateBook < Mutations::BaseMutation 6 | 7 | null false 8 | 9 | argument :id, ID, 'the ID of the book to edit', required: true 10 | argument :title, String, 'the new title', required: true 11 | argument :description, String, 'the new description', required: false 12 | 13 | field :book, Types::BookType, null: true 14 | field :errors, [String], null: false 15 | 16 | def resolve(id:, name:, description:) 17 | book = Book.find_by(id: id) 18 | if book&.update!(name: name, description: description) 19 | { 20 | book: book, 21 | errors: [] 22 | } 23 | else 24 | { 25 | book: nil, 26 | errors: book.errors.full_messages 27 | } 28 | end 29 | end 30 | 31 | end 32 | 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /app/graphql/rest_graphql_schema.rb: -------------------------------------------------------------------------------- 1 | class RestGraphqlSchema < GraphQL::Schema 2 | 3 | query Types::QueryType 4 | mutation Types::MutationType 5 | 6 | use GraphQL::Batch 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/graphql/types/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/app/graphql/types/.keep -------------------------------------------------------------------------------- /app/graphql/types/author_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class AuthorType < Types::BaseObject 4 | 5 | description 'Author of the books' 6 | 7 | field :id, ID, null: false 8 | field :name, String, "Author's name", null: false 9 | field :books, [Types::BookType], null: true 10 | 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /app/graphql/types/base_enum.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BaseEnum < GraphQL::Schema::Enum 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/types/base_input_object.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BaseInputObject < GraphQL::Schema::InputObject 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/types/base_interface.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | module BaseInterface 4 | 5 | include GraphQL::Schema::Interface 6 | 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/graphql/types/base_object.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BaseObject < GraphQL::Schema::Object 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/types/base_scalar.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BaseScalar < GraphQL::Schema::Scalar 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/types/base_union.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BaseUnion < GraphQL::Schema::Union 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/graphql/types/book_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class BookType < Types::BaseObject 4 | 5 | field :id, ID, "Book's id", null: false 6 | field :title, String, "Book's title", null: false 7 | field :description, String, "Book's description", null: true 8 | field :authors, [Types::AuthorType], null: false 9 | 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /app/graphql/types/mutation_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class MutationType < Types::BaseObject 4 | 5 | field :create_author, mutation: Mutations::AuthorMutations::CreateAuthor 6 | field :destroy_author, mutation: Mutations::AuthorMutations::DestroyAuthor 7 | field :update_author, mutation: Mutations::AuthorMutations::UpdateAuthor 8 | field :create_book, mutation: Mutations::BookMutations::CreateBook 9 | field :destroy_book, mutation: Mutations::BookMutations::DestroyBook 10 | field :update_book, mutation: Mutations::BookMutations::UpdateBook 11 | 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /app/graphql/types/query_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | 3 | class QueryType < Types::BaseObject 4 | 5 | field :authors, [Types::AuthorType], null: false 6 | field :books, [Types::BookType], null: false 7 | 8 | field :author, Types::AuthorType, null: true do 9 | argument :id, ID, required: true 10 | end 11 | 12 | field :book, Types::BookType, null: true do 13 | argument :id, ID, required: true 14 | end 15 | 16 | def authors 17 | Author.all 18 | end 19 | 20 | def author(id:) 21 | Author.find_by(id: id) 22 | end 23 | 24 | def books 25 | Book.all 26 | end 27 | 28 | def book(id:) 29 | Book.find_by(id: id) 30 | end 31 | 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | 3 | default from: 'from@example.com' 4 | layout 'mailer' 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | 3 | self.abstract_class = true 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/models/author.rb: -------------------------------------------------------------------------------- 1 | class Author < ApplicationRecord 2 | 3 | validates :name, presence: true 4 | 5 | has_many :authorships, dependent: :destroy 6 | has_many :books, through: :authorships, dependent: :destroy 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/models/authorship.rb: -------------------------------------------------------------------------------- 1 | class Authorship < ApplicationRecord 2 | 3 | belongs_to :author 4 | belongs_to :book, dependent: :destroy 5 | 6 | validates :author_id, uniqueness: { scope: :book_id, message: "Same author can't be duplicated" } 7 | validates :author_id, :book_id, presence: true 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/models/book.rb: -------------------------------------------------------------------------------- 1 | class Book < ApplicationRecord 2 | 3 | validates :title, presence: true 4 | 5 | has_many :authorships, dependent: :nullify 6 | has_many :authors, through: :authorships 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/serializers/author_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AuthorSerializer < ActiveModel::Serializer 4 | 5 | attributes :id, :name 6 | has_many :books, through: :authorships 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/serializers/book_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class BookSerializer < ActiveModel::Serializer 4 | 5 | attributes :id, :title, :description 6 | has_many :authors, through: :authorships 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a starting point to setup your application. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?('config/database.yml') 22 | # cp 'config/database.yml.sample', 'config/database.yml' 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! 'bin/rails db:setup' 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! 'bin/rails log:clear tmp:clear' 30 | 31 | puts "\n== Restarting application server ==" 32 | system! 'bin/rails restart' 33 | end 34 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a way to update your development environment automatically. 14 | # Add necessary update steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | puts "\n== Updating database ==" 21 | system! 'bin/rails db:migrate' 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system! 'bin/rails log:clear tmp:clear' 25 | 26 | puts "\n== Restarting application server ==" 27 | system! 'bin/rails restart' 28 | end 29 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | require "sprockets/railtie" 3 | 4 | require "rails" 5 | # Pick the frameworks you want: 6 | require "active_model/railtie" 7 | require "active_job/railtie" 8 | require "active_record/railtie" 9 | require "active_storage/engine" 10 | require "action_controller/railtie" 11 | require "action_mailer/railtie" 12 | require "action_view/railtie" 13 | require "action_cable/engine" 14 | # require "sprockets/railtie" 15 | # require "rails/test_unit/railtie" 16 | 17 | # Require the gems listed in Gemfile, including any gems 18 | # you've limited to :test, :development, or :production. 19 | Bundler.require(*Rails.groups) 20 | 21 | module RestGraphql 22 | class Application < Rails::Application 23 | # Initialize configuration defaults for originally generated Rails version. 24 | config.load_defaults 5.2 25 | 26 | # Settings in config/environments/* take precedence over those specified here. 27 | # Application configuration can go into files in config/initializers 28 | # -- all .rb files in that directory are automatically loaded after loading 29 | # the framework and any gems in your application. 30 | 31 | # Only loads a smaller set of middleware suitable for API only apps. 32 | # Middleware like session, flash, cookies can be added back manually. 33 | # Skip views, helpers and assets when generating a new resource. 34 | config.api_only = true 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: rest-graphql_production 11 | -------------------------------------------------------------------------------- /config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | Hqi1/a2cG0ekYqPr7KoG20bU7M9b9IA4jfFGUd6CLzVJNEuu0NjUR0sJ/mGsL1KNvx2gfGbmt7+e9OdWL/lz6xQ9XAMeFn8n59PmArJK4HXNEWdvDYP0CVBJUFQJM/IHae4oMoBs0R9d1ixFEXP24TAasxmoe/7J5/w0UBK9pUky2l4rTaNvmSHlijvbMG0ufZPwFSOcuEBnqWqfiDTfAVvydCJ7Lw8vJzQ3Q0rFSGgR8gX5PbRcolAatJ0tZJwzfwAQT40u/C4bALfiOAxLQtDp1kntr5NZTP2Ar29P/LIlH3xhat6WZ2qTUPHMaeHUABoXmgvf6bKBzyxeduzIjLud8TgS+n8MrAUZlU/6pk4F+sobJpj7+b3ztAjMPmmGAB5ZTNdLJ873KxEzAq0imf48S2WodCGiQ/bF--FoqSRvUsd4QM14V2--X68sxwWkiZmRdALuM6hRDA== -------------------------------------------------------------------------------- /config/database.yml.example: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: 5 5 | username: postgres 6 | password: 7 | development: 8 | <<: *default 9 | database: application_development 10 | test: 11 | <<: *default 12 | database: application_test 13 | production: 14 | <<: *default 15 | database: application_production 16 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | 20 | config.cache_store = :memory_store 21 | config.public_file_server.headers = { 22 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 23 | } 24 | else 25 | config.action_controller.perform_caching = false 26 | 27 | config.cache_store = :null_store 28 | end 29 | 30 | # Store uploaded files on the local file system (see config/storage.yml for options) 31 | config.active_storage.service = :local 32 | 33 | # Don't care if the mailer can't send. 34 | config.action_mailer.raise_delivery_errors = false 35 | 36 | config.action_mailer.perform_caching = false 37 | 38 | # Print deprecation notices to the Rails logger. 39 | config.active_support.deprecation = :log 40 | 41 | # Raise an error on page load if there are pending migrations. 42 | config.active_record.migration_error = :page_load 43 | 44 | # Highlight code that triggered database queries in logs. 45 | config.active_record.verbose_query_logs = true 46 | 47 | 48 | # Raises error for missing translations 49 | # config.action_view.raise_on_missing_translations = true 50 | 51 | # Use an evented file watcher to asynchronously detect changes in source code, 52 | # routes, locales, etc. This feature depends on the listen gem. 53 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 54 | end 55 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 19 | # config.require_master_key = true 20 | 21 | # Disable serving static files from the `/public` folder by default since 22 | # Apache or NGINX already handles this. 23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 24 | 25 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 26 | # config.action_controller.asset_host = 'http://assets.example.com' 27 | 28 | # Specifies the header that your server uses for sending files. 29 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 30 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 31 | 32 | # Store uploaded files on the local file system (see config/storage.yml for options) 33 | config.active_storage.service = :local 34 | 35 | # Mount Action Cable outside main process or domain 36 | # config.action_cable.mount_path = nil 37 | # config.action_cable.url = 'wss://example.com/cable' 38 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 39 | 40 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 41 | # config.force_ssl = true 42 | 43 | # Use the lowest log level to ensure availability of diagnostic information 44 | # when problems arise. 45 | config.log_level = :debug 46 | 47 | # Prepend all log lines with the following tags. 48 | config.log_tags = [ :request_id ] 49 | 50 | # Use a different cache store in production. 51 | # config.cache_store = :mem_cache_store 52 | 53 | # Use a real queuing backend for Active Job (and separate queues per environment) 54 | # config.active_job.queue_adapter = :resque 55 | # config.active_job.queue_name_prefix = "rest-graphql_#{Rails.env}" 56 | 57 | config.action_mailer.perform_caching = false 58 | 59 | # Ignore bad email addresses and do not raise email delivery errors. 60 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 61 | # config.action_mailer.raise_delivery_errors = false 62 | 63 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 64 | # the I18n.default_locale when a translation cannot be found). 65 | config.i18n.fallbacks = true 66 | 67 | # Send deprecation notices to registered listeners. 68 | config.active_support.deprecation = :notify 69 | 70 | # Use default logging formatter so that PID and timestamp are not suppressed. 71 | config.log_formatter = ::Logger::Formatter.new 72 | 73 | # Use a different logger for distributed setups. 74 | # require 'syslog/logger' 75 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 76 | 77 | if ENV["RAILS_LOG_TO_STDOUT"].present? 78 | logger = ActiveSupport::Logger.new(STDOUT) 79 | logger.formatter = config.log_formatter 80 | config.logger = ActiveSupport::TaggedLogging.new(logger) 81 | end 82 | 83 | # Do not dump schema after migrations. 84 | config.active_record.dump_schema_after_migration = false 85 | end 86 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | 31 | # Store uploaded files on the local file system in a temporary directory 32 | config.active_storage.service = :test 33 | 34 | config.action_mailer.perform_caching = false 35 | 36 | # Tell Action Mailer not to deliver emails to the real world. 37 | # The :test delivery method accumulates sent emails in the 38 | # ActionMailer::Base.deliveries array. 39 | config.action_mailer.delivery_method = :test 40 | 41 | # Print deprecation notices to the stderr. 42 | config.active_support.deprecation = :stderr 43 | 44 | # Raises error for missing translations 45 | # config.action_view.raise_on_missing_translations = true 46 | end 47 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Avoid CORS issues when API is called from the frontend app. 4 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 5 | 6 | # Read more: https://github.com/cyu/rack-cors 7 | 8 | # Rails.application.config.middleware.insert_before 0, Rack::Cors do 9 | # allow do 10 | # origins 'example.com' 11 | # 12 | # resource '*', 13 | # headers: :any, 14 | # methods: [:get, :post, :put, :patch, :delete, :options, :head] 15 | # end 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at http://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. 30 | # 31 | # preload_app! 32 | 33 | # Allow puma to be restarted by `rails restart` command. 34 | plugin :tmp_restart 35 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | if Rails.env.development? 4 | mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql" 5 | end 6 | 7 | post "/graphql", to: "graphql#execute" 8 | namespace :api do 9 | namespace :v1 do 10 | resources :authors 11 | resources :books 12 | end 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /db/migrate/20181203105241_create_books.rb: -------------------------------------------------------------------------------- 1 | class CreateBooks < ActiveRecord::Migration[5.2] 2 | def change 3 | create_table :books do |t| 4 | t.string :title 5 | t.string :description 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20181203105334_create_authors.rb: -------------------------------------------------------------------------------- 1 | class CreateAuthors < ActiveRecord::Migration[5.2] 2 | def change 3 | create_table :authors do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20181203120508_create_authorships.rb: -------------------------------------------------------------------------------- 1 | class CreateAuthorships < ActiveRecord::Migration[5.2] 2 | def change 3 | create_table :authorships do |t| 4 | t.references :author 5 | t.references :book 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 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: 2018_12_03_120508) do 14 | 15 | # These are extensions that must be enabled in order to support this database 16 | enable_extension "plpgsql" 17 | 18 | create_table "authors", force: :cascade do |t| 19 | t.string "name" 20 | t.datetime "created_at", null: false 21 | t.datetime "updated_at", null: false 22 | end 23 | 24 | create_table "authorships", force: :cascade do |t| 25 | t.bigint "author_id" 26 | t.bigint "book_id" 27 | t.index ["author_id"], name: "index_authorships_on_author_id" 28 | t.index ["book_id"], name: "index_authorships_on_book_id" 29 | end 30 | 31 | create_table "books", force: :cascade do |t| 32 | t.string "title" 33 | t.string "description" 34 | t.datetime "created_at", null: false 35 | t.datetime "updated_at", null: false 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/lib/tasks/.keep -------------------------------------------------------------------------------- /public/images/result1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/public/images/result1.png -------------------------------------------------------------------------------- /public/images/result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/public/images/result2.png -------------------------------------------------------------------------------- /public/images/result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/public/images/result3.png -------------------------------------------------------------------------------- /public/images/result4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/public/images/result4.png -------------------------------------------------------------------------------- /public/images/result5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/public/images/result5.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /spec/models/author_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Author, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/book_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Book, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' 2 | SimpleCov.start do 3 | add_filter ['/spec/', '/config/'] 4 | end 5 | 6 | ENV['RAILS_ENV'] ||= 'test' 7 | require File.expand_path('../../config/environment', __FILE__) 8 | 9 | abort("The Rails environment is running in production mode!") if Rails.env.production? 10 | require 'rspec/rails' 11 | 12 | Shoulda::Matchers.configure do |config| 13 | config.integrate do |with| 14 | with.test_framework :rspec 15 | with.library :rails 16 | end 17 | end 18 | 19 | ActiveRecord::Migration.maintain_test_schema! 20 | 21 | RSpec.configure do |config| 22 | config.include FactoryBot::Syntax::Methods 23 | 24 | config.before(:each) do 25 | DatabaseCleaner.strategy = :truncation 26 | DatabaseCleaner.clean 27 | end 28 | 29 | config.use_transactional_fixtures = false 30 | 31 | config.infer_spec_type_from_file_location! 32 | config.filter_rails_from_backtrace! 33 | end 34 | -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/rest-graphql/e3f3e86ab0cb3f0209494cba8ed1127be550f2e1/vendor/.keep --------------------------------------------------------------------------------