From 54e5e9c7b809c19b035717b4a5d60298162d1547 Mon Sep 17 00:00:00 2001 From: Hernan Zamora Date: Wed, 2 Aug 2023 21:52:28 -0300 Subject: [PATCH 1/4] Installed rswag to create docs - Documentation created --- Gemfile | 2 + Gemfile.lock | 17 ++++ app/controllers/api/v1/comments_controller.rb | 11 ++- app/controllers/api/v1/posts_controller.rb | 2 + config/initializers/rswag_api.rb | 14 ++++ config/initializers/rswag_ui.rb | 16 ++++ config/routes.rb | 2 + spec/api/v1/comments_controller_spec.rb | 38 +++++++++ spec/api/v1/posts_controller_spec.rb | 18 +++++ spec/requests/posts_controller_spec.rb | 56 -------------- spec/requests/users_controller_spec.rb | 44 ----------- spec/swagger_helper.rb | 43 +++++++++++ swagger/v1/swagger.yaml | 77 +++++++++++++++++++ 13 files changed, 237 insertions(+), 103 deletions(-) create mode 100644 config/initializers/rswag_api.rb create mode 100644 config/initializers/rswag_ui.rb create mode 100644 spec/api/v1/comments_controller_spec.rb create mode 100644 spec/api/v1/posts_controller_spec.rb delete mode 100644 spec/requests/posts_controller_spec.rb delete mode 100644 spec/requests/users_controller_spec.rb create mode 100644 spec/swagger_helper.rb create mode 100644 swagger/v1/swagger.yaml diff --git a/Gemfile b/Gemfile index 8878f3b..e1032d7 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,8 @@ gem 'active_model_serializers', '~> 0.10.13' gem 'jwt' +gem 'rswag' + # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' gem 'rails', '~> 7.0.6' diff --git a/Gemfile.lock b/Gemfile.lock index 30386b1..b526460 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -119,6 +119,8 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.3) + json-schema (3.0.0) + addressable (>= 2.8) jsonapi-renderer (0.2.2) jwt (2.7.1) language_server-protocol (3.17.0.3) @@ -223,6 +225,20 @@ GEM rspec-mocks (~> 3.12) rspec-support (~> 3.12) rspec-support (3.12.1) + rswag (2.10.1) + rswag-api (= 2.10.1) + rswag-specs (= 2.10.1) + rswag-ui (= 2.10.1) + rswag-api (2.10.1) + railties (>= 3.1, < 7.1) + rswag-specs (2.10.1) + activesupport (>= 3.1, < 7.1) + json-schema (>= 2.2, < 4.0) + railties (>= 3.1, < 7.1) + rspec-core (>= 2.14) + rswag-ui (2.10.1) + actionpack (>= 3.1, < 7.1) + railties (>= 3.1, < 7.1) rubocop (1.54.2) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -299,6 +315,7 @@ DEPENDENCIES rails (~> 7.0.6) rails-controller-testing rspec-rails + rswag rubocop (>= 1.0, < 2.0) selenium-webdriver sprockets-rails diff --git a/app/controllers/api/v1/comments_controller.rb b/app/controllers/api/v1/comments_controller.rb index fd782aa..53dafdf 100644 --- a/app/controllers/api/v1/comments_controller.rb +++ b/app/controllers/api/v1/comments_controller.rb @@ -6,6 +6,8 @@ def index post = user.posts.find(params[:post_id]) comments = post.comments render json: comments + rescue StandardError => e + render json: { error: e.message }, status: :bad_request end def create @@ -18,9 +20,12 @@ def create author: user ) - new_comment.save - render json: { success: 'Comment added!' } + if new_comment.save + render json: { success: 'Comment added!' }, status: :created + else + render json: { error: new_comment.errors.full_messages }, status: :bad_request + end rescue StandardError => e - render json: { error: e.message } + render json: { error: e.message }, status: :bad_request end end diff --git a/app/controllers/api/v1/posts_controller.rb b/app/controllers/api/v1/posts_controller.rb index 38781e0..02d1049 100644 --- a/app/controllers/api/v1/posts_controller.rb +++ b/app/controllers/api/v1/posts_controller.rb @@ -3,5 +3,7 @@ def index posts = User.find(params['user_id']).posts render json: posts + rescue StandardError + render json: { error: 'User not found' }, status: :bad_request end end diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb new file mode 100644 index 0000000..4d72f68 --- /dev/null +++ b/config/initializers/rswag_api.rb @@ -0,0 +1,14 @@ +Rswag::Api.configure do |c| + + # Specify a root folder where Swagger JSON files are located + # This is used by the Swagger middleware to serve requests for API descriptions + # NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure + # that it's configured to generate files in the same folder + c.swagger_root = Rails.root.to_s + '/swagger' + + # Inject a lambda function to alter the returned Swagger prior to serialization + # The function will have access to the rack env for the current request + # For example, you could leverage this to dynamically assign the "host" property + # + #c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } +end diff --git a/config/initializers/rswag_ui.rb b/config/initializers/rswag_ui.rb new file mode 100644 index 0000000..0a768c1 --- /dev/null +++ b/config/initializers/rswag_ui.rb @@ -0,0 +1,16 @@ +Rswag::Ui.configure do |c| + + # List the Swagger endpoints that you want to be documented through the + # swagger-ui. The first parameter is the path (absolute or relative to the UI + # host) to the corresponding endpoint and the second is a title that will be + # displayed in the document selector. + # NOTE: If you're using rspec-api to expose Swagger files + # (under swagger_root) as JSON or YAML endpoints, then the list below should + # correspond to the relative paths for those endpoints. + + c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs' + + # Add Basic Auth in case your API is private + # c.basic_auth_enabled = true + # c.basic_auth_credentials 'username', 'password' +end diff --git a/config/routes.rb b/config/routes.rb index 118bb8c..a2bf90d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do + mount Rswag::Ui::Engine => '/api-docs' + mount Rswag::Api::Engine => '/api-docs' namespace :api do namespace :v1 do post 'sessions' => 'sessions#create' diff --git a/spec/api/v1/comments_controller_spec.rb b/spec/api/v1/comments_controller_spec.rb new file mode 100644 index 0000000..71af6f6 --- /dev/null +++ b/spec/api/v1/comments_controller_spec.rb @@ -0,0 +1,38 @@ +require 'swagger_helper' + +RSpec.describe 'api/v1/comments', type: :request do + path '/api/v1/users/{user_id}/posts/{post_id}/comments' do + parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' + parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' + + get 'List all comments on a user\'s post' do + tags 'Comments' + response 200, 'Successful' do + run_test! + end + end + + post 'Create a comment on a user\'s post' do + tags 'Comments' + consumes 'application/json' + + parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true + parameter name: 'text', in: :body, schema: { + type: :object, + properties: { + text: { type: :string } + }, + required: [:text] + } + description 'Your API token is generated on sign up. It is located on your user profile page.' + + response 201, 'Comment created' do + run_test! + end + + response 400, 'Comment not created' do + run_test! + end + end + end +end \ No newline at end of file diff --git a/spec/api/v1/posts_controller_spec.rb b/spec/api/v1/posts_controller_spec.rb new file mode 100644 index 0000000..5f3a6ea --- /dev/null +++ b/spec/api/v1/posts_controller_spec.rb @@ -0,0 +1,18 @@ +require 'swagger_helper' + +RSpec.describe 'api/v1/posts', type: :request do + path '/api/v1/users/{user_id}/posts' do + get 'List all posts for user with user_id' do + tags 'Posts' + parameter name: 'user_id', in: :path, type: :string, description: 'user_id' + + response 200, 'Successful' do + run_test! + end + + response 400, 'User not found' do + run_test! + end + end + end +end \ No newline at end of file diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb deleted file mode 100644 index 06f8ca5..0000000 --- a/spec/requests/posts_controller_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'rails_helper' - -RSpec.describe '/users/posts', type: :request do - let(:user) do - User.create( - name: 'Hernán Zamora', - photo: 'https://cdn2.iconfinder.com/data/icons/random-outline-3/48/random_14-512.png', - bio: 'Software Engineer', - posts_counter: 0 - ) - end - - let(:first_post) do - Post.create( - author: user, - title: 'First Post', - text: 'Testing text for first post', - likes_counter: 0, - comments_counter: 0 - ) - end - - let(:second_post) do - Post.create( - author: user, - title: 'Second Post', - text: 'Testing text for second post', - likes_counter: 0, - comments_counter: 0 - ) - end - - before do - user - first_post - second_post - end - - describe 'Get /index' do - it 'Shows the posts for a given user' do - get "/users/#{user.id}/posts" - expect(response).to render_template 'posts/index' - expect(response.body).to include('First Post') - expect(response.body).to include('Second Post') - end - end - - describe 'Get /show' do - it 'Shows the post details' do - get "/users/#{user.id}/posts/#{first_post.id}" - expect(response).to render_template 'posts/show' - expect(response.body).to include user.name - expect(response.body).to include('Testing text for first post') - end - end -end diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb deleted file mode 100644 index 646e9dc..0000000 --- a/spec/requests/users_controller_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'rails_helper' - -RSpec.describe '/users', type: :request do - let(:user) do - User.create( - name: 'Hernán Zamora', - photo: 'https://cdn2.iconfinder.com/data/icons/random-outline-3/48/random_14-512.png', - bio: 'Software Engineer', - posts_counter: 0 - ) - end - - let(:user2) do - User.create( - name: 'Martin Escobar', - photo: 'https://cdn2.iconfinder.com/data/icons/random-outline-3/48/random_14-512.png', - bio: 'Actor', - posts_counter: 0 - ) - end - - before do - user - user2 - end - - describe 'GET /index' do - it 'Shows all the users' do - get '/' - expect(response).to render_template 'users/index' - expect(response.body).to include('Hernán Zamora') - expect(response.body).to include('Martin Escobar') - end - end - - describe 'GET /show' do - it 'Shows details for a given user' do - get "/users/#{user.id}" - expect(response).to render_template 'users/show' - expect(response.body).to include('Hernán Zamora') - expect(response.body).to include('Software Engineer') - end - end -end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb new file mode 100644 index 0000000..8f71560 --- /dev/null +++ b/spec/swagger_helper.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.configure do |config| + # Specify a root folder where Swagger JSON files are generated + # NOTE: If you're using the rswag-api to serve API descriptions, you'll need + # to ensure that it's configured to serve Swagger from the same folder + config.swagger_root = Rails.root.join('swagger').to_s + + # Define one or more Swagger documents and provide global metadata for each one + # When you run the 'rswag:specs:swaggerize' rake task, the complete Swagger will + # be generated at the provided relative path under swagger_root + # By default, the operations defined in spec files are added to the first + # document below. You can override this behavior by adding a swagger_doc tag to the + # the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json' + config.swagger_docs = { + 'v1/swagger.yaml' => { + openapi: '3.0.1', + info: { + title: 'API V1', + version: 'v1' + }, + paths: {}, + servers: [ + { + url: 'https://{defaultHost}', + variables: { + defaultHost: { + default: 'www.example.com' + } + } + } + ] + } + } + + # Specify the format of the output Swagger file when running 'rswag:specs:swaggerize'. + # The swagger_docs configuration option has the filename including format in + # the key, this may want to be changed to avoid putting yaml in json files. + # Defaults to json. Accepts ':json' and ':yaml'. + config.swagger_format = :yaml +end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml new file mode 100644 index 0000000..9643cf3 --- /dev/null +++ b/swagger/v1/swagger.yaml @@ -0,0 +1,77 @@ +--- +openapi: 3.0.1 +info: + title: API V1 + version: v1 +paths: + "/api/v1/users/{user_id}/posts/{post_id}/comments": + parameters: + - name: user_id + in: path + description: ID of a user + required: true + schema: + type: string + - name: post_id + in: path + description: ID of a post + required: true + schema: + type: string + get: + summary: List all comments on a user's post + tags: + - Comments + responses: + '200': + description: Successful + post: + summary: Create a comment on a user's post + tags: + - Comments + parameters: + - name: X-Token + in: header + description: API token + required: true + schema: + type: string + description: Your API token is generated on sign up. It is located on your user + profile page. + responses: + '201': + description: Comment created + '400': + description: Comment not created + requestBody: + content: + application/json: + schema: + type: object + properties: + text: + type: string + required: + - text + "/api/v1/users/{user_id}/posts": + get: + summary: List all posts for user with user_id + tags: + - Posts + parameters: + - name: user_id + in: path + description: user_id + required: true + schema: + type: string + responses: + '200': + description: Successful + '400': + description: User not found +servers: +- url: https://{defaultHost} + variables: + defaultHost: + default: www.example.com From 76dac152e1b962220eb4a31cec58311a68834961 Mon Sep 17 00:00:00 2001 From: Hernan Zamora Date: Wed, 2 Aug 2023 21:52:45 -0300 Subject: [PATCH 2/4] changed files --- spec/api/v1/comments_controller_spec.rb | 64 ++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/spec/api/v1/comments_controller_spec.rb b/spec/api/v1/comments_controller_spec.rb index 71af6f6..a8a97c0 100644 --- a/spec/api/v1/comments_controller_spec.rb +++ b/spec/api/v1/comments_controller_spec.rb @@ -1,38 +1,38 @@ -require 'swagger_helper' +# require 'swagger_helper' -RSpec.describe 'api/v1/comments', type: :request do - path '/api/v1/users/{user_id}/posts/{post_id}/comments' do - parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' - parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' +# RSpec.describe 'api/v1/comments', type: :request do +# path '/api/v1/users/{user_id}/posts/{post_id}/comments' do +# parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' +# parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' - get 'List all comments on a user\'s post' do - tags 'Comments' - response 200, 'Successful' do - run_test! - end - end +# get 'List all comments on a user\'s post' do +# tags 'Comments' +# response 200, 'Successful' do +# run_test! +# end +# end - post 'Create a comment on a user\'s post' do - tags 'Comments' - consumes 'application/json' +# post 'Create a comment on a user\'s post' do +# tags 'Comments' +# consumes 'application/json' - parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true - parameter name: 'text', in: :body, schema: { - type: :object, - properties: { - text: { type: :string } - }, - required: [:text] - } - description 'Your API token is generated on sign up. It is located on your user profile page.' +# parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true +# parameter name: 'text', in: :body, schema: { +# type: :object, +# properties: { +# text: { type: :string } +# }, +# required: [:text] +# } +# description 'Your API token is generated on sign up. It is located on your user profile page.' - response 201, 'Comment created' do - run_test! - end +# response 201, 'Comment created' do +# run_test! +# end - response 400, 'Comment not created' do - run_test! - end - end - end -end \ No newline at end of file +# response 400, 'Comment not created' do +# run_test! +# end +# end +# end +# end \ No newline at end of file From e388e0f825889703e068b3968b77fa7c91c92ae9 Mon Sep 17 00:00:00 2001 From: Cristian Zambrano Date: Wed, 2 Aug 2023 20:59:00 -0400 Subject: [PATCH 3/4] Add comment controller spec --- spec/api/v1/comments_controller_spec.rb | 64 ++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/spec/api/v1/comments_controller_spec.rb b/spec/api/v1/comments_controller_spec.rb index a8a97c0..3b386ea 100644 --- a/spec/api/v1/comments_controller_spec.rb +++ b/spec/api/v1/comments_controller_spec.rb @@ -1,38 +1,38 @@ -# require 'swagger_helper' +require 'swagger_helper' -# RSpec.describe 'api/v1/comments', type: :request do -# path '/api/v1/users/{user_id}/posts/{post_id}/comments' do -# parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' -# parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' +RSpec.describe 'api/v1/comments', type: :request do +path '/api/v1/users/{user_id}/posts/{post_id}/comments' do + parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' + parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' -# get 'List all comments on a user\'s post' do -# tags 'Comments' -# response 200, 'Successful' do -# run_test! -# end -# end + get 'List all comments on a user\'s post' do + tags 'Comments' + response 200, 'Successful' do + run_test! + end + end -# post 'Create a comment on a user\'s post' do -# tags 'Comments' -# consumes 'application/json' + post 'Create a comment on a user\'s post' do + tags 'Comments' + consumes 'application/json' -# parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true -# parameter name: 'text', in: :body, schema: { -# type: :object, -# properties: { -# text: { type: :string } -# }, -# required: [:text] -# } -# description 'Your API token is generated on sign up. It is located on your user profile page.' + parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true + parameter name: 'text', in: :body, schema: { + type: :object, + properties: { + text: { type: :string } + }, + required: [:text] + } + description 'Your API token is generated on sign up. It is located on your user profile page.' -# response 201, 'Comment created' do -# run_test! -# end + response 201, 'Comment created' do + run_test! + end -# response 400, 'Comment not created' do -# run_test! -# end -# end -# end -# end \ No newline at end of file + response 400, 'Comment not created' do + run_test! + end + end +end +end From 64b0a95aadf780e89ab6f35b96ccdc39819e5fda Mon Sep 17 00:00:00 2001 From: Hernan Zamora Date: Wed, 2 Aug 2023 22:06:25 -0300 Subject: [PATCH 4/4] Fixed linters --- spec/api/v1/comments_controller_spec.rb | 32 ++++++++++++------------- spec/api/v1/posts_controller_spec.rb | 2 +- spec/swagger_helper.rb | 2 -- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/spec/api/v1/comments_controller_spec.rb b/spec/api/v1/comments_controller_spec.rb index 3b386ea..87128ea 100644 --- a/spec/api/v1/comments_controller_spec.rb +++ b/spec/api/v1/comments_controller_spec.rb @@ -1,38 +1,38 @@ require 'swagger_helper' RSpec.describe 'api/v1/comments', type: :request do -path '/api/v1/users/{user_id}/posts/{post_id}/comments' do + path '/api/v1/users/{user_id}/posts/{post_id}/comments' do parameter name: 'user_id', in: :path, type: :string, description: 'ID of a user' parameter name: 'post_id', in: :path, type: :string, description: 'ID of a post' get 'List all comments on a user\'s post' do - tags 'Comments' - response 200, 'Successful' do + tags 'Comments' + response 200, 'Successful' do run_test! - end + end end post 'Create a comment on a user\'s post' do - tags 'Comments' - consumes 'application/json' + tags 'Comments' + consumes 'application/json' - parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true - parameter name: 'text', in: :body, schema: { + parameter name: 'X-Token', in: :header, type: :string, description: 'API token', required: true + parameter name: 'text', in: :body, schema: { type: :object, properties: { - text: { type: :string } + text: { type: :string } }, required: [:text] - } - description 'Your API token is generated on sign up. It is located on your user profile page.' + } + description 'Your API token is generated on sign up. It is located on your user profile page.' - response 201, 'Comment created' do + response 201, 'Comment created' do run_test! - end + end - response 400, 'Comment not created' do + response 400, 'Comment not created' do run_test! + end end - end -end + end end diff --git a/spec/api/v1/posts_controller_spec.rb b/spec/api/v1/posts_controller_spec.rb index 5f3a6ea..6cb97af 100644 --- a/spec/api/v1/posts_controller_spec.rb +++ b/spec/api/v1/posts_controller_spec.rb @@ -15,4 +15,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 8f71560..feaae2b 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - require 'rails_helper' RSpec.configure do |config|