From 9ff121deb09a6ec878f673b0addb7f2eef8aee82 Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Wed, 5 Jul 2023 15:45:45 +0700 Subject: [PATCH 01/11] Use Ruby 3.0.1 --- .tool-versions | 2 +- Gemfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.tool-versions b/.tool-versions index a56897b0..cd028710 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ nodejs 18.15.0 -ruby 3.0.6 +ruby 3.0.1 yarn 1.22.19 diff --git a/Gemfile b/Gemfile index f52021fd..762ea993 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby '3.0.6' +ruby '3.0.1' # Backend gem 'rails', '7.0.4.3' # Latest stable From 7aa5d3bb5bde32ebf994721b19293b2520f9ddb4 Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Wed, 5 Jul 2023 16:28:07 +0700 Subject: [PATCH 02/11] Add routes, controller --- .../api/docs/openapi_controller.rb | 9 ++++++ app/views/api/docs/openapi/show.html.erb | 30 +++++++++++++++++++ config/routes.rb | 4 +++ package.json | 7 ++++- 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 app/controllers/api/docs/openapi_controller.rb create mode 100644 app/views/api/docs/openapi/show.html.erb diff --git a/app/controllers/api/docs/openapi_controller.rb b/app/controllers/api/docs/openapi_controller.rb new file mode 100644 index 00000000..3ada7e22 --- /dev/null +++ b/app/controllers/api/docs/openapi_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module API + module Docs + class OpenapiController < ApplicationController + def show; end + end + end +end diff --git a/app/views/api/docs/openapi/show.html.erb b/app/views/api/docs/openapi/show.html.erb new file mode 100644 index 00000000..1aef37af --- /dev/null +++ b/app/views/api/docs/openapi/show.html.erb @@ -0,0 +1,30 @@ + + + + + + SwaggerUI + + + +
+ + + + + diff --git a/config/routes.rb b/config/routes.rb index e4c36dbf..7391ef51 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,5 +35,9 @@ resources :surveys, only: %i[index show] resource :users, only: :show, path: :me end + + namespace :docs do + get '/openapi', to: 'openapi#show' + end end end diff --git a/package.json b/package.json index e4a59e81..399a86fb 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,12 @@ "build:sass": "sass app/assets/stylesheets/application.scss:app/assets/builds/application.css --no-source-map --load-path=node_modules --load-path=app/assets/stylesheets", "build:postcss": "postcss app/assets/builds/application.css --dir app/assets/builds", "build:css": "yarn build:sass && yarn build:postcss", - "build": "yarn build:js && yarn build:css" + "build": "yarn build:js && yarn build:css", + "lint:docs:yml": "eslint docs/openapi --ext .yml --color", + "lint:docs:openapi": "spectral lint docs/openapi/openapi.yml -F error", + "lint:docs:dev": "yarn lint:docs:yml && yarn lint:docs:openapi", + "lint:docs:public": "yarn build:docs && eslint public/openapi.yml --color --no-ignore && spectral lint public/openapi.yml -F error", + "build:docs": "swagger-cli bundle docs/openapi/openapi.yml --outfile public/openapi.yml --type yaml" }, "dependencies": { "@fullhuman/postcss-purgecss": "2.3.0", From 8991bfb67d2fe738b285ffb9247dce54907f790b Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Wed, 5 Jul 2023 16:54:46 +0700 Subject: [PATCH 03/11] Add local server --- docs/openapi/openapi.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/openapi/openapi.yml diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml new file mode 100644 index 00000000..f9734f8d --- /dev/null +++ b/docs/openapi/openapi.yml @@ -0,0 +1,14 @@ +--- +openapi: 3.0.0 +info: + title: Nimble Survey API Documentation + description: This is the API documentation for Nimble Survey + version: 1.0.0 + +servers: + - local: http://localhost:{port}/api/v1 + description: Local server + variables: + port: 3000 + +paths: From 225566bda9809e00a2c520d09a34c217955257cd Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Thu, 6 Jul 2023 15:31:28 +0700 Subject: [PATCH 04/11] Use redoc style --- app/views/api/docs/openapi/show.html.erb | 43 ++++++++++-------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/app/views/api/docs/openapi/show.html.erb b/app/views/api/docs/openapi/show.html.erb index 1aef37af..bd2494aa 100644 --- a/app/views/api/docs/openapi/show.html.erb +++ b/app/views/api/docs/openapi/show.html.erb @@ -1,30 +1,23 @@ - + + - - SwaggerUI - + + + - -
- - - - + + + + + From d07ea861b644cdd90d764eba8ad479ef9e28e15f Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Thu, 6 Jul 2023 15:39:03 +0700 Subject: [PATCH 05/11] Revert "Use redoc style" This reverts commit 225566bda9809e00a2c520d09a34c217955257cd. --- app/views/api/docs/openapi/show.html.erb | 43 ++++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/app/views/api/docs/openapi/show.html.erb b/app/views/api/docs/openapi/show.html.erb index bd2494aa..1aef37af 100644 --- a/app/views/api/docs/openapi/show.html.erb +++ b/app/views/api/docs/openapi/show.html.erb @@ -1,23 +1,30 @@ - - + - - - + + SwaggerUI + - - - - - + +
+ + + + From 88a7f7c1efc448a81ea854c5768d78603faa5a4f Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Thu, 6 Jul 2023 16:28:12 +0700 Subject: [PATCH 06/11] =?UTF-8?q?Define=20the=20first=20API=20endpoint=20?= =?UTF-8?q?=E2=80=94=20Login=20with=20email?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/openapi/openapi.yml | 125 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index f9734f8d..9019b07b 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -6,9 +6,132 @@ info: version: 1.0.0 servers: - - local: http://localhost:{port}/api/v1 + - url: https://survey-api.nimblehq.co/api/v1 + description: Production server + - url: https://survey-api-staging.nimblehq.co/api/v1 + description: Staging server + - url: http://localhost:{port}/api/v1 description: Local server variables: port: 3000 paths: + /oauth/token: + post: + summary: Login with email + description: Request an Access Token using either email/password or a refresh token.
You will then send this code to this endpoint to exchange it for an Access Token. The returned Access Token can then be used to to make Survey API calls. + requestBody: + required: true + description: A request body for request a new OAuth 2.0 Token. + content: + application/json: + schema: + type: object + + required: + - grant_type + - email + - password + - client_id + - client_secret + + properties: + grant_type: + type: string + description: |- + The type of request being made, either using a client-side obtained + authorization code, a refresh token, a JWT assertion, client credentials + grant or another access token for the purpose of downscoping a token. In this API, please use `password` + example: password + email: + type: string + description: |- + The email of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + example: dev@nimblehq.co + password: + type: string + description: |- + The password of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + example: password123 + client_id: + type: string + description: |- + The Client ID of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. + example: 6GbE8dhoz519l2N_F99StqoOs6Tcmm1rXgda4q__rIw + client_secret: + type: string + description: |- + The client secret of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. + example: _ayfIm7BeUAhx2W1OUqi20fwO3uNxfo1QstyKlFCgHw + responses: + '200': + description: A response body for a new OAuth 2.0 token + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: string + description: |- + The identifier of the access token + example: 123 + type: + type: string + description: |- + The type of the access token + example: token + attributes: + type: object + description: |- + A request for a new OAuth 2.0 token + properties: + access_token: + type: string + example: 123-f2i0CG6MDsf-wJE9FyYrhSGAOtxBkhYWDI + token_type: + type: string + example: Bearer + expires_in: + type: number + example: 7200 + refresh_token: + type: string + example: l27GNT0kmkPbnEaUxniXyu4cHfPyWFr00kZTX5oWKA6c + created_at: + type: number + example: 1681974651 + + '400': + description: Bad request + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + source: + type: string + example: Doorkeeper::OAuth::Error + detail: + type: string + example: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. + code: + type: string + example: invalid_grant + From b9908a9ac3c7a6332132d57e2f56c1acbc7761a3 Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Fri, 7 Jul 2023 11:06:13 +0700 Subject: [PATCH 07/11] =?UTF-8?q?Define=20the=20second=20API=20endpoint=20?= =?UTF-8?q?=E2=80=94=20Get=20Survey=20List?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/openapi/examples/responses/surveys.json | 58 ++++++++++ docs/openapi/openapi.yml | 112 ++++++++++++++++++- 2 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 docs/openapi/examples/responses/surveys.json diff --git a/docs/openapi/examples/responses/surveys.json b/docs/openapi/examples/responses/surveys.json new file mode 100644 index 00000000..39f90811 --- /dev/null +++ b/docs/openapi/examples/responses/surveys.json @@ -0,0 +1,58 @@ +{ + "bangkok": { + "value": { + "data": [ + { + "id": "d5de6a8f8f5f1cfe51bc", + "type": "survey_simple", + "attributes": { + "title": "Scarlett Bangkok", + "description": "We'd love ot hear from you!", + "thank_email_above_threshold": "Dear {name},

Thank you for visiting Scarlett Wine Bar & Restaurant at Pullman Bangkok Hotel G  and for taking the time to complete our guest feedback survey!

Your feedback is very important to us and each survey is read individually by the management and owners shortly after it is sent. We discuss comments and suggestions at our daily meetings and use them to constantly improve our services.

We would very much appreciate it if you could take a few more moments and review us on TripAdvisor regarding your recent visit. By clicking here you will be directed to our page. 

Thank you once again and we look forward to seeing you soon!

The Team at Scarlett Wine Bar & Restaurant 
Pullman Bangkok Hotel G", + "thank_email_below_threshold": "Dear {name},

Thank you for visiting 
Uno Mas at Centara Central World  and for taking the time to complete our customer feedback survey.

The Team at Scarlett Wine Bar & Restaurant Pullman Bangkok Hotel G", + "is_active": true, + "cover_image_url": "https://dhdbhh0jsld0o.cloudfront.net/m/1ea51560991bcb7d00d0_", + "created_at": "2017-01-23T07:48:12.991Z", + "active_at": "2015-10-08T07:04:00.000Z", + "inactive_at": null, + "survey_type": "Restaurant" + } + } + ], + "meta": { + "page": 1, + "pages": 20, + "page_size": 1, + "records": 20 + } + } + }, + "riverside": { + "value": { + "data": [ + { + "id": "ed1d4f0ff19a56073a14", + "type": "survey_simple", + "attributes": { + "title": "ibis Bangkok Riverside", + "description": "We'd love to hear from you!", + "thank_email_above_threshold": "Dear {name},

Thank you for visiting Beach Republic and for taking the time to complete our brief survey. We are thrilled that you enjoyed your time with us! If you have a moment, we would be greatly appreciate it if you could leave a short review on TripAdvisor. It helps to spread the word and let others know about the Beach Republic Revolution!

Thank you again and we look forward to welcoming you back soon.

Sincerely,

Beach Republic Team", + "thank_email_below_threshold": "Dear {name},

Thank you for visiting Beach Republic and for taking the time to complete our brief survey. We are constantly striving to improve and your feedback allows us to help improve the experience for you on your next visit. Each survey is read individually by senior staff and discussed with the team in daily meetings. 

Thank you again and we look forward to welcoming you back soon.

Sincerely,

Beach Republic Team", + "is_active": true, + "cover_image_url": "https://dhdbhh0jsld0o.cloudfront.net/m/287db81c5e4242412cc0_", + "created_at": "2017-01-23T03:32:24.585Z", + "active_at": "2016-01-22T04:12:00.000Z", + "inactive_at": null, + "survey_type": "Hotel" + } + } + ], + "meta": { + "page": 2, + "pages": 20, + "page_size": 1, + "records": 20 + } + } + } +} diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index 9019b07b..5d489aee 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -10,10 +10,8 @@ servers: description: Production server - url: https://survey-api-staging.nimblehq.co/api/v1 description: Staging server - - url: http://localhost:{port}/api/v1 + - url: http://localhost:3000/api/v1 description: Local server - variables: - port: 3000 paths: /oauth/token: @@ -135,3 +133,111 @@ paths: type: string example: invalid_grant + /surveys: + get: + summary: Survey list + description: Call this API to get the data of a list of survey + parameters: + - in: query + name: page[number] + schema: + type: integer + default: 1 + description: The page number of the survey list. + example: 1 + - in: query + name: page[size] + schema: + type: integer + default: 5 + description: The page size of the survey list that client side expects to get. + example: 10 + + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + detail: + type: string + example: The access token is invalid + code: + type: string + example: invalid_token + '200': + description: A response body for a survey list + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + attributes: + type: object + properties: + title: + type: string + description: + type: string + thank_email_above_threshold: + type: string + thank_email_below_threshold: + type: string + is_active: + type: boolean + cover_image_url: + type: string + created_at: + type: string + format: date-time + active_at: + type: string + format: date-time + inactive_at: + type: string + format: date-time + nullable: true + survey_type: + type: string + meta: + type: object + properties: + page: + type: integer + pages: + type: integer + page_size: + type: integer + records: + type: integer + examples: + $ref: './examples/responses/surveys.json' + +security: + - basicAuth: [] + - bearerAuth: [] + +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer From dba2789846af6e7a85b912e1aa787d5092b238c0 Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Fri, 7 Jul 2023 11:56:52 +0700 Subject: [PATCH 08/11] Separate schemas and paths into files --- Gemfile.lock | 9 +- docs/openapi/examples/requests/token.json | 7 + docs/openapi/examples/responses/token.json | 13 ++ docs/openapi/openapi.yml | 213 +-------------------- docs/openapi/paths/oauth/token.yml | 25 +++ docs/openapi/paths/surveys.yml | 32 ++++ docs/openapi/schemas/requests/token.yml | 41 ++++ docs/openapi/schemas/responses/surveys.yml | 24 +++ docs/openapi/schemas/responses/token.yml | 15 ++ docs/openapi/schemas/statuses/400.yml | 20 ++ docs/openapi/schemas/statuses/401.yml | 17 ++ docs/openapi/schemas/survey.yml | 26 +++ docs/openapi/schemas/token.yml | 14 ++ 13 files changed, 243 insertions(+), 213 deletions(-) create mode 100644 docs/openapi/examples/requests/token.json create mode 100644 docs/openapi/examples/responses/token.json create mode 100644 docs/openapi/paths/oauth/token.yml create mode 100644 docs/openapi/paths/surveys.yml create mode 100644 docs/openapi/schemas/requests/token.yml create mode 100644 docs/openapi/schemas/responses/surveys.yml create mode 100644 docs/openapi/schemas/responses/token.yml create mode 100644 docs/openapi/schemas/statuses/400.yml create mode 100644 docs/openapi/schemas/statuses/401.yml create mode 100644 docs/openapi/schemas/survey.yml create mode 100644 docs/openapi/schemas/token.yml diff --git a/Gemfile.lock b/Gemfile.lock index 1b9c29ed..63f00e16 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -230,6 +230,7 @@ GEM method_source (1.0.0) mini_magick (4.12.0) mini_mime (1.1.2) + mini_portile2 (2.8.2) minitest (5.18.0) msgpack (1.7.0) nap (1.1.0) @@ -244,6 +245,9 @@ GEM net-protocol nio4r (2.5.9) no_proxy_fix (0.1.2) + nokogiri (1.14.2) + mini_portile2 (~> 2.8.0) + racc (~> 1.4) nokogiri (1.14.2-x86_64-darwin) racc (~> 1.4) nokogiri (1.14.2-x86_64-linux) @@ -448,6 +452,7 @@ GEM zeitwerk (2.6.7) PLATFORMS + ruby x86_64-darwin-22 x86_64-linux @@ -514,7 +519,7 @@ DEPENDENCIES webmock RUBY VERSION - ruby 3.0.6p216 + ruby 3.0.1p64 BUNDLED WITH - 2.2.33 + 2.4.12 diff --git a/docs/openapi/examples/requests/token.json b/docs/openapi/examples/requests/token.json new file mode 100644 index 00000000..a392ca10 --- /dev/null +++ b/docs/openapi/examples/requests/token.json @@ -0,0 +1,7 @@ +{ + "grant_type": "password", + "email": "dev@nimblehq.co", + "password": "password123", + "client_id": "6GbE8dhoz519l2N_F99StqoOs6Tcmm1rXgda4q__rIw", + "client_secret": "_ayfIm7BeUAhx2W1OUqi20fwO3uNxfo1QstyKlFCgHw" +} diff --git a/docs/openapi/examples/responses/token.json b/docs/openapi/examples/responses/token.json new file mode 100644 index 00000000..e58fa0b0 --- /dev/null +++ b/docs/openapi/examples/responses/token.json @@ -0,0 +1,13 @@ +{ + "data": { + "id": "123", + "type": "token", + "attributes": { + "access_token": "123-f2i0CG6MDsf-wJE9FyYrhSGAOtxBkhYWDI", + "token_type": "Bearer", + "expires_in": 7200, + "refresh_token": "l27GNT0kmkPbnEaUxniXyu4cHfPyWFr00kZTX5oWKA6c", + "created_at": 1681974651 + } + } +} diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index 5d489aee..bf3498eb 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -15,219 +15,10 @@ servers: paths: /oauth/token: - post: - summary: Login with email - description: Request an Access Token using either email/password or a refresh token.
You will then send this code to this endpoint to exchange it for an Access Token. The returned Access Token can then be used to to make Survey API calls. - requestBody: - required: true - description: A request body for request a new OAuth 2.0 Token. - content: - application/json: - schema: - type: object - - required: - - grant_type - - email - - password - - client_id - - client_secret - - properties: - grant_type: - type: string - description: |- - The type of request being made, either using a client-side obtained - authorization code, a refresh token, a JWT assertion, client credentials - grant or another access token for the purpose of downscoping a token. In this API, please use `password` - example: password - email: - type: string - description: |- - The email of the user requesting an access token. - - Used in combination with `password` as the `grant_type`. - example: dev@nimblehq.co - password: - type: string - description: |- - The password of the user requesting an access token. - - Used in combination with `password` as the `grant_type`. - example: password123 - client_id: - type: string - description: |- - The Client ID of the application requesting an access token. - - Used in combination with `password` as the `grant_type`. - example: 6GbE8dhoz519l2N_F99StqoOs6Tcmm1rXgda4q__rIw - client_secret: - type: string - description: |- - The client secret of the application requesting an access token. - - Used in combination with `password` as the `grant_type`. - example: _ayfIm7BeUAhx2W1OUqi20fwO3uNxfo1QstyKlFCgHw - responses: - '200': - description: A response body for a new OAuth 2.0 token - content: - application/json: - schema: - type: object - properties: - data: - type: object - properties: - id: - type: string - description: |- - The identifier of the access token - example: 123 - type: - type: string - description: |- - The type of the access token - example: token - attributes: - type: object - description: |- - A request for a new OAuth 2.0 token - properties: - access_token: - type: string - example: 123-f2i0CG6MDsf-wJE9FyYrhSGAOtxBkhYWDI - token_type: - type: string - example: Bearer - expires_in: - type: number - example: 7200 - refresh_token: - type: string - example: l27GNT0kmkPbnEaUxniXyu4cHfPyWFr00kZTX5oWKA6c - created_at: - type: number - example: 1681974651 - - '400': - description: Bad request - content: - application/json: - schema: - type: object - properties: - errors: - type: array - items: - type: object - properties: - source: - type: string - example: Doorkeeper::OAuth::Error - detail: - type: string - example: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. - code: - type: string - example: invalid_grant + $ref: './paths/oauth/token.yml' /surveys: - get: - summary: Survey list - description: Call this API to get the data of a list of survey - parameters: - - in: query - name: page[number] - schema: - type: integer - default: 1 - description: The page number of the survey list. - example: 1 - - in: query - name: page[size] - schema: - type: integer - default: 5 - description: The page size of the survey list that client side expects to get. - example: 10 - - responses: - '401': - description: Unauthorized - content: - application/json: - schema: - type: object - properties: - errors: - type: array - items: - type: object - properties: - detail: - type: string - example: The access token is invalid - code: - type: string - example: invalid_token - '200': - description: A response body for a survey list - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - type: object - properties: - id: - type: string - type: - type: string - attributes: - type: object - properties: - title: - type: string - description: - type: string - thank_email_above_threshold: - type: string - thank_email_below_threshold: - type: string - is_active: - type: boolean - cover_image_url: - type: string - created_at: - type: string - format: date-time - active_at: - type: string - format: date-time - inactive_at: - type: string - format: date-time - nullable: true - survey_type: - type: string - meta: - type: object - properties: - page: - type: integer - pages: - type: integer - page_size: - type: integer - records: - type: integer - examples: - $ref: './examples/responses/surveys.json' + $ref: './paths/surveys.yml' security: - basicAuth: [] diff --git a/docs/openapi/paths/oauth/token.yml b/docs/openapi/paths/oauth/token.yml new file mode 100644 index 00000000..9cc4e0be --- /dev/null +++ b/docs/openapi/paths/oauth/token.yml @@ -0,0 +1,25 @@ +post: + summary: Login with email + description: Request an Access Token using either email/password or a refresh token.
You will then send this code to this endpoint to exchange it for an Access Token. The returned Access Token can then be used to to make Survey API calls. + requestBody: + required: true + description: A request body for request a new OAuth 2.0 Token. + content: + application/json: + schema: + $ref: '../../schemas/requests/token.yml' + example: + $ref: '../../examples/requests/token.json' + responses: + '200': + description: A response body for a new OAuth 2.0 token + content: + application/json: + schema: + $ref: '../../schemas/responses/token.yml' + example: + $ref: '../../examples/responses/token.json' + '400': + $ref: '../../schemas/statuses/400.yml' + '401': + $ref: '../../schemas/statuses/401.yml' diff --git a/docs/openapi/paths/surveys.yml b/docs/openapi/paths/surveys.yml new file mode 100644 index 00000000..2dc9c71f --- /dev/null +++ b/docs/openapi/paths/surveys.yml @@ -0,0 +1,32 @@ +get: + summary: Survey list + description: Call this API to get the data of a list of survey + parameters: + - in: query + name: page[number] + schema: + type: integer + default: 1 + description: The page number of the survey list. + example: 1 + - in: query + name: page[size] + schema: + type: integer + default: 5 + description: The page size of the survey list that client side expects to get. + example: 10 + + responses: + '200': + description: A response body for a survey list + content: + application/json: + schema: + $ref: '../schemas/responses/surveys.yml' + examples: + $ref: '../examples/responses/surveys.json' + '400': + $ref: '../schemas/statuses/400.yml' + '401': + $ref: '../schemas/statuses/401.yml' diff --git a/docs/openapi/schemas/requests/token.yml b/docs/openapi/schemas/requests/token.yml new file mode 100644 index 00000000..31ca78e6 --- /dev/null +++ b/docs/openapi/schemas/requests/token.yml @@ -0,0 +1,41 @@ + +type: object + +required: + - grant_type + - email + - password + - client_id + - client_secret + +properties: + grant_type: + type: string + description: |- + The type of request being made, either using a client-side obtained + authorization code, a refresh token, a JWT assertion, client credentials + grant or another access token for the purpose of downscoping a token. In this API, please use `password` + email: + type: string + description: |- + The email of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + password: + type: string + description: |- + The password of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + client_id: + type: string + description: |- + The Client ID of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. + client_secret: + type: string + description: |- + The client secret of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. diff --git a/docs/openapi/schemas/responses/surveys.yml b/docs/openapi/schemas/responses/surveys.yml new file mode 100644 index 00000000..65e5aa71 --- /dev/null +++ b/docs/openapi/schemas/responses/surveys.yml @@ -0,0 +1,24 @@ +type: object +properties: + data: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + attributes: + $ref: '../survey.yml' + meta: + type: object + properties: + page: + type: integer + pages: + type: integer + page_size: + type: integer + records: + type: integer diff --git a/docs/openapi/schemas/responses/token.yml b/docs/openapi/schemas/responses/token.yml new file mode 100644 index 00000000..cee47369 --- /dev/null +++ b/docs/openapi/schemas/responses/token.yml @@ -0,0 +1,15 @@ +type: object +properties: + data: + type: object + properties: + id: + type: string + description: |- + The identifier of the access token + type: + type: string + description: |- + The type of the access token + attributes: + $ref: '../token.yml' diff --git a/docs/openapi/schemas/statuses/400.yml b/docs/openapi/schemas/statuses/400.yml new file mode 100644 index 00000000..550ec228 --- /dev/null +++ b/docs/openapi/schemas/statuses/400.yml @@ -0,0 +1,20 @@ +description: Bad request +content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + source: + type: string + example: Doorkeeper::OAuth::Error + detail: + type: string + example: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. + code: + type: string + example: invalid_grant diff --git a/docs/openapi/schemas/statuses/401.yml b/docs/openapi/schemas/statuses/401.yml new file mode 100644 index 00000000..6c5e319a --- /dev/null +++ b/docs/openapi/schemas/statuses/401.yml @@ -0,0 +1,17 @@ +description: Unauthorized +content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + detail: + type: string + example: The access token is invalid + code: + type: string + example: invalid_token diff --git a/docs/openapi/schemas/survey.yml b/docs/openapi/schemas/survey.yml new file mode 100644 index 00000000..70b3e667 --- /dev/null +++ b/docs/openapi/schemas/survey.yml @@ -0,0 +1,26 @@ +type: object +properties: + title: + type: string + description: + type: string + thank_email_above_threshold: + type: string + thank_email_below_threshold: + type: string + is_active: + type: boolean + cover_image_url: + type: string + created_at: + type: string + format: date-time + active_at: + type: string + format: date-time + inactive_at: + type: string + format: date-time + nullable: true + survey_type: + type: string diff --git a/docs/openapi/schemas/token.yml b/docs/openapi/schemas/token.yml new file mode 100644 index 00000000..04de658e --- /dev/null +++ b/docs/openapi/schemas/token.yml @@ -0,0 +1,14 @@ +type: object +description: |- + A request for a new OAuth 2.0 token +properties: + access_token: + type: string + token_type: + type: string + expires_in: + type: number + refresh_token: + type: string + created_at: + type: number From e90309e1496ef106b1d273949ea5fbbefed813af Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Fri, 7 Jul 2023 11:58:57 +0700 Subject: [PATCH 09/11] Use redoc style --- app/views/api/docs/openapi/show.html.erb | 41 ++++++++++-------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/app/views/api/docs/openapi/show.html.erb b/app/views/api/docs/openapi/show.html.erb index 1aef37af..18b1e659 100644 --- a/app/views/api/docs/openapi/show.html.erb +++ b/app/views/api/docs/openapi/show.html.erb @@ -1,30 +1,23 @@ - + + - - SwaggerUI - + + - -
- - - - + + + + + From b6d9f296f6b2f7b0af3c9435d2853a9b5873075b Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Fri, 7 Jul 2023 12:01:15 +0700 Subject: [PATCH 10/11] Revert "Use Ruby 3.0.1" This reverts commit 9ff121deb09a6ec878f673b0addb7f2eef8aee82. --- .tool-versions | 2 +- Gemfile | 2 +- Gemfile.lock | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.tool-versions b/.tool-versions index cd028710..a56897b0 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ nodejs 18.15.0 -ruby 3.0.1 +ruby 3.0.6 yarn 1.22.19 diff --git a/Gemfile b/Gemfile index 762ea993..f52021fd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby '3.0.1' +ruby '3.0.6' # Backend gem 'rails', '7.0.4.3' # Latest stable diff --git a/Gemfile.lock b/Gemfile.lock index 63f00e16..1b9c29ed 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -230,7 +230,6 @@ GEM method_source (1.0.0) mini_magick (4.12.0) mini_mime (1.1.2) - mini_portile2 (2.8.2) minitest (5.18.0) msgpack (1.7.0) nap (1.1.0) @@ -245,9 +244,6 @@ GEM net-protocol nio4r (2.5.9) no_proxy_fix (0.1.2) - nokogiri (1.14.2) - mini_portile2 (~> 2.8.0) - racc (~> 1.4) nokogiri (1.14.2-x86_64-darwin) racc (~> 1.4) nokogiri (1.14.2-x86_64-linux) @@ -452,7 +448,6 @@ GEM zeitwerk (2.6.7) PLATFORMS - ruby x86_64-darwin-22 x86_64-linux @@ -519,7 +514,7 @@ DEPENDENCIES webmock RUBY VERSION - ruby 3.0.1p64 + ruby 3.0.6p216 BUNDLED WITH - 2.4.12 + 2.2.33 From c403842c01264b854ee56a7fd01a64bc543a79a0 Mon Sep 17 00:00:00 2001 From: Sang Huynh Date: Wed, 19 Jul 2023 15:28:46 +0700 Subject: [PATCH 11/11] Update routes --- .../api/docs/openapi_controller.rb | 9 - config/routes.rb | 2 +- public/openapi.yml | 279 ++++++++++++++++++ .../show.html.erb => public/redoc.html | 0 4 files changed, 280 insertions(+), 10 deletions(-) delete mode 100644 app/controllers/api/docs/openapi_controller.rb create mode 100644 public/openapi.yml rename app/views/api/docs/openapi/show.html.erb => public/redoc.html (100%) diff --git a/app/controllers/api/docs/openapi_controller.rb b/app/controllers/api/docs/openapi_controller.rb deleted file mode 100644 index 3ada7e22..00000000 --- a/app/controllers/api/docs/openapi_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module API - module Docs - class OpenapiController < ApplicationController - def show; end - end - end -end diff --git a/config/routes.rb b/config/routes.rb index 7391ef51..05a44747 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,7 +37,7 @@ end namespace :docs do - get '/openapi', to: 'openapi#show' + get '/openapi', to: redirect('/redoc.html') end end end diff --git a/public/openapi.yml b/public/openapi.yml new file mode 100644 index 00000000..e471ced3 --- /dev/null +++ b/public/openapi.yml @@ -0,0 +1,279 @@ +openapi: 3.0.0 +info: + title: Nimble Survey API Documentation + description: This is the API documentation for Nimble Survey + version: 1.0.0 +servers: + - url: 'https://survey-api.nimblehq.co/api/v1' + description: Production server + - url: 'https://survey-api-staging.nimblehq.co/api/v1' + description: Staging server + - url: 'http://localhost:3000/api/v1' + description: Local server +paths: + /oauth/token: + post: + summary: Login with email + description: Request an Access Token using either email/password or a refresh token.
You will then send this code to this endpoint to exchange it for an Access Token. The returned Access Token can then be used to to make Survey API calls. + requestBody: + required: true + description: A request body for request a new OAuth 2.0 Token. + content: + application/json: + schema: + type: object + required: + - grant_type + - email + - password + - client_id + - client_secret + properties: + grant_type: + type: string + description: |- + The type of request being made, either using a client-side obtained + authorization code, a refresh token, a JWT assertion, client credentials + grant or another access token for the purpose of downscoping a token. In this API, please use `password` + email: + type: string + description: |- + The email of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + password: + type: string + description: |- + The password of the user requesting an access token. + + Used in combination with `password` as the `grant_type`. + client_id: + type: string + description: |- + The Client ID of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. + client_secret: + type: string + description: |- + The client secret of the application requesting an access token. + + Used in combination with `password` as the `grant_type`. + example: + grant_type: password + email: dev@nimblehq.co + password: password123 + client_id: 6GbE8dhoz519l2N_F99StqoOs6Tcmm1rXgda4q__rIw + client_secret: _ayfIm7BeUAhx2W1OUqi20fwO3uNxfo1QstyKlFCgHw + responses: + '200': + description: A response body for a new OAuth 2.0 token + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: string + description: The identifier of the access token + type: + type: string + description: The type of the access token + attributes: + type: object + description: A request for a new OAuth 2.0 token + properties: + access_token: + type: string + token_type: + type: string + expires_in: + type: number + refresh_token: + type: string + created_at: + type: number + example: + data: + id: '123' + type: token + attributes: + access_token: 123-f2i0CG6MDsf-wJE9FyYrhSGAOtxBkhYWDI + token_type: Bearer + expires_in: 7200 + refresh_token: l27GNT0kmkPbnEaUxniXyu4cHfPyWFr00kZTX5oWKA6c + created_at: 1681974651 + '400': + $ref: '#/paths/~1surveys/get/responses/400' + '401': + $ref: '#/paths/~1surveys/get/responses/401' + /surveys: + get: + summary: Survey list + description: Call this API to get the data of a list of survey + parameters: + - in: query + name: 'page[number]' + schema: + type: integer + default: 1 + description: The page number of the survey list. + example: 1 + - in: query + name: 'page[size]' + schema: + type: integer + default: 5 + description: The page size of the survey list that client side expects to get. + example: 10 + responses: + '200': + description: A response body for a survey list + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + attributes: + type: object + properties: + title: + type: string + description: + type: string + thank_email_above_threshold: + type: string + thank_email_below_threshold: + type: string + is_active: + type: boolean + cover_image_url: + type: string + created_at: + type: string + format: date-time + active_at: + type: string + format: date-time + inactive_at: + type: string + format: date-time + nullable: true + survey_type: + type: string + meta: + type: object + properties: + page: + type: integer + pages: + type: integer + page_size: + type: integer + records: + type: integer + examples: + bangkok: + value: + data: + - id: d5de6a8f8f5f1cfe51bc + type: survey_simple + attributes: + title: Scarlett Bangkok + description: We'd love ot hear from you! + thank_email_above_threshold: 'Dear {name},

Thank you for visiting Scarlett Wine Bar & Restaurant at Pullman Bangkok Hotel G  and for taking the time to complete our guest feedback survey!

Your feedback is very important to us and each survey is read individually by the management and owners shortly after it is sent. We discuss comments and suggestions at our daily meetings and use them to constantly improve our services.

We would very much appreciate it if you could take a few more moments and review us on TripAdvisor regarding your recent visit. By clicking here you will be directed to our page. 

Thank you once again and we look forward to seeing you soon!

The Team at Scarlett Wine Bar & Restaurant 
Pullman Bangkok Hotel G' + thank_email_below_threshold: 'Dear {name},

Thank you for visiting 
Uno Mas at Centara Central World  and for taking the time to complete our customer feedback survey.

The Team at Scarlett Wine Bar & Restaurant Pullman Bangkok Hotel G' + is_active: true + cover_image_url: 'https://dhdbhh0jsld0o.cloudfront.net/m/1ea51560991bcb7d00d0_' + created_at: '2017-01-23T07:48:12.991Z' + active_at: '2015-10-08T07:04:00.000Z' + inactive_at: null + survey_type: Restaurant + meta: + page: 1 + pages: 20 + page_size: 1 + records: 20 + riverside: + value: + data: + - id: ed1d4f0ff19a56073a14 + type: survey_simple + attributes: + title: ibis Bangkok Riverside + description: We'd love to hear from you! + thank_email_above_threshold: 'Dear {name},

Thank you for visiting Beach Republic and for taking the time to complete our brief survey. We are thrilled that you enjoyed your time with us! If you have a moment, we would be greatly appreciate it if you could leave a short review on TripAdvisor. It helps to spread the word and let others know about the Beach Republic Revolution!

Thank you again and we look forward to welcoming you back soon.

Sincerely,

Beach Republic Team' + thank_email_below_threshold: 'Dear {name},

Thank you for visiting Beach Republic and for taking the time to complete our brief survey. We are constantly striving to improve and your feedback allows us to help improve the experience for you on your next visit. Each survey is read individually by senior staff and discussed with the team in daily meetings. 

Thank you again and we look forward to welcoming you back soon.

Sincerely,

Beach Republic Team' + is_active: true + cover_image_url: 'https://dhdbhh0jsld0o.cloudfront.net/m/287db81c5e4242412cc0_' + created_at: '2017-01-23T03:32:24.585Z' + active_at: '2016-01-22T04:12:00.000Z' + inactive_at: null + survey_type: Hotel + meta: + page: 2 + pages: 20 + page_size: 1 + records: 20 + '400': + description: Bad request + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + source: + type: string + example: 'Doorkeeper::OAuth::Error' + detail: + type: string + example: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.' + code: + type: string + example: invalid_grant + '401': + description: Unauthorized + content: + application/json: + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + detail: + type: string + example: The access token is invalid + code: + type: string + example: invalid_token +security: + - basicAuth: [] + - bearerAuth: [] +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer diff --git a/app/views/api/docs/openapi/show.html.erb b/public/redoc.html similarity index 100% rename from app/views/api/docs/openapi/show.html.erb rename to public/redoc.html