28_introduce_rswag #35

Merged
philipp merged 46 commits from 28_introduce_rswag into develop 2023-01-05 13:45:47 +01:00
6 changed files with 278 additions and 51 deletions
Showing only changes of commit 614aef746f - Show all commits

View file

@ -5,9 +5,11 @@ like listing open orders, updating the ordergroup's order, and listing financial
transactions. Not all Foodsoft functionality is available through the API, but transactions. Not all Foodsoft functionality is available through the API, but
we're open for new additions. we're open for new additions.
The API is documented using [Open API 2.0](https://github.com/OAI/OpenAPI-Specification) The API is documented using [Open API 3.0.1](https://github.com/OAI/OpenAPI-Specification)
/ [Swagger](https://swagger.io/) in [swagger.v1.yml](swagger.v1.yml). / [Swagger](https://swagger.io/) in [swagger.yaml](/swagger/v1/swagger.yaml).
This provides a machine-readable reference that is used to provide documentation. This provides a machine-readable reference that is used to provide documentation.
It is generated by [rswag](https://github.com/rswag) wich also provides api-tests.
It can be generated running `RAILS_ENV=test rails rswag`.
**Note:** the current OAuth scopes may be subject to change, until the next release of Foodsoft. **Note:** the current OAuth scopes may be subject to change, until the next release of Foodsoft.

View file

@ -0,0 +1,96 @@
require 'swagger_helper'
describe 'User API', type: :request do
include ApiHelper
path '/user' do
get 'info about the currently logged-in user' do
tags 'User'
produces 'application/json'
let(:api_scopes) { ['user:read'] }
let(:other_user1) { create :user }
let(:user) { create :user }
let(:other_user2) { create :user }
response '200', 'success' do
schema type: :object,
properties: {
user: {
type: :object,
properties: {
id: {
type: :integer
},
name: {
type: :string,
description: 'full name'
},
email: {
type: :string,
description: 'email address'
},
locale: {
type: :string,
description: 'language code'
}
},
required: %w[id name email]
}
}
run_test! do |response|
data = JSON.parse(response.body)
expect(data['user']['id']).to eq(user.id)
end
end
it_handles_invalid_token_and_scope
end
end
path '/user/financial_overview' do
get 'financial summary about the currently logged-in user' do
tags 'User', 'FinancialTransaction'
produces 'application/json'
let!(:user) { create :user, :ordergroup }
response 200, 'success' do
schema type: :object,
properties: {
account_balance: {
type: :number,
description: 'booked accout balance of ordergroup'
},
available_funds: {
type: :number,
description: 'fund available to order articles'
},
financial_transaction_class_sums: {
type: :object,
properties: {
id: {
type: :integer,
description: 'id of the financial transaction class'
},
name: {
type: :string,
description: 'name of the financial transaction class'
},
amount: {
type: :number,
description: 'sum of the amounts belonging to the financial transaction class'
},
required: %w[id name amount]
},
required: %w[account_balance available_funds financial_transaction_class_sums]
}
}
let(:api_scopes) { ['finance:user'] }
run_test!
end
it_handles_invalid_token_and_scope
end
end
end

View file

@ -1,39 +0,0 @@
require 'swagger_helper'
describe 'Users API', type: :request do
include ApiHelper
path '/user' do
get 'info about the currently logged-in user' do
tags 'User'
produces 'application/json'
let(:api_scopes) { ['user:read'] }
let(:other_user_1) { create :user }
let(:user) { create :user }
let(:other_user_2) { create :user }
response '200', 'success' do
run_test! do |response|
data = JSON.parse(response.body)
expect(data['user']['id']).to eq(user.id)
end
end
it_handles_invalid_token_and_scope
end
end
path '/user/financial_overview' do
get 'financial summary about the currently logged-in user' do
tags 'User', 'FinancialTransaction'
let!(:user) { create :user, :ordergroup }
response 200, 'success' do
let(:api_scopes) { ['finance:user'] }
run_test!
end
it_handles_invalid_token_and_scope
end
end
end

View file

@ -7,12 +7,12 @@ module ApiHelper
let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token } let(:api_access_token) { create(:oauth2_access_token, resource_owner_id: user.id, scopes: api_scopes&.join(' ')).token }
let(:Authorization) { "Bearer #{api_access_token}" } let(:Authorization) { "Bearer #{api_access_token}" }
# TODO: not needed anymore?
def self.it_handles_invalid_token() def self.it_handles_invalid_token()
context 'with invalid access token' do context 'with invalid access token' do
let(:Authorization) { 'abc' } let(:Authorization) { 'abc' }
response 401, 'not logged-in' do response 401, 'not logged-in' do
schema '$ref' => '#/components/schemas/Error401'
run_test! run_test!
end end
end end
@ -23,6 +23,7 @@ module ApiHelper
let(:api_scopes) { ['none'] } let(:api_scopes) { ['none'] }
response 403, 'missing scope' do response 403, 'missing scope' do
schema '$ref' => '#/components/schemas/Error403'
run_test! run_test!
end end
end end
@ -33,13 +34,4 @@ module ApiHelper
it_handles_invalid_scope(*args) it_handles_invalid_scope(*args)
end end
end end
# Add authentication to parameters for {Swagger::RspecHelpers#validate}
# @param params [Hash] Query parameters
# @return Query parameters with authentication header
# @see Swagger::RspecHelpers#validate
# def api_auth(params = {})
# { '_headers' => { 'Authorization' => api_authorization } }.deep_merge(params)
# end
# TODO: not needed anymore
end end

View file

@ -23,6 +23,69 @@ RSpec.configure do |config|
}, },
paths: {}, paths: {},
components: { components: {
schemas: {
Error: {
type: :object,
properties: {
error: {
type: :string,
description: 'error code'
},
error_description: {
type: :string,
description: 'human-readable error message (localized)'
}
}
},
Error401: {
type: :object,
properties: {
error: {
type: :string,
description: '<tt>unauthorized</tt>'
},
error_description: {
'$ref': '#/components/schemas/Error/properties/error_description'
}
}
},
Error403: {
type: :object,
properties: {
error: {
type: :string,
description: '<tt>forbidden</tt> or <tt>invalid_scope</tt>'
},
error_description: {
'$ref': '#/components/schemas/Error/properties/error_description'
}
}
},
Error404: {
type: :object,
properties: {
error: {
type: :string,
description: '<tt>not_found</tt>'
},
error_description: {
'$ref': '#/components/schemas/Error/properties/error_description'
}
}
},
Error422: {
type: :object,
properties: {
error: {
type: :string,
description: 'unprocessable entity'
},
error_description: {
'$ref': '#/components/schemas/Error/properties/error_description'
}
}
}
},
securitySchemes: { securitySchemes: {
oauth2: { oauth2: {
type: :oauth2, type: :oauth2,

View file

@ -12,10 +12,41 @@ paths:
responses: responses:
'200': '200':
description: success description: success
content:
application/json:
schema:
type: object
properties:
user:
type: object
properties:
id:
type: integer
name:
type: string
description: full name
email:
type: string
description: email address
locale:
type: string
description: language code
required:
- id
- name
- email
'401': '401':
description: not logged-in description: not logged-in
content:
application/json:
schema:
"$ref": "#/components/schemas/Error401"
'403': '403':
description: missing scope description: missing scope
content:
application/json:
schema:
"$ref": "#/components/schemas/Error403"
"/user/financial_overview": "/user/financial_overview":
get: get:
summary: financial summary about the currently logged-in user summary: financial summary about the currently logged-in user
@ -25,11 +56,93 @@ paths:
responses: responses:
'200': '200':
description: success description: success
content:
application/json:
schema:
type: object
properties:
account_balance:
type: number
description: booked accout balance of ordergroup
available_funds:
type: number
description: fund available to order articles
financial_transaction_class_sums:
type: object
properties:
id:
type: integer
description: id of the financial transaction class
name:
type: string
description: name of the financial transaction class
amount:
type: number
description: sum of the amounts belonging to the financial
transaction class
required:
- id
- name
- amount
required:
- account_balance
- available_funds
- financial_transaction_class_sums
'401': '401':
description: not logged-in description: not logged-in
content:
application/json:
schema:
"$ref": "#/components/schemas/Error401"
'403': '403':
description: missing scope description: missing scope
content:
application/json:
schema:
"$ref": "#/components/schemas/Error403"
components: components:
schemas:
Error:
type: object
properties:
error:
type: string
description: error code
error_description:
type: string
description: human-readable error message (localized)
Error401:
type: object
properties:
error:
type: string
description: "<tt>unauthorized</tt>"
error_description:
"$ref": "#/components/schemas/Error/properties/error_description"
Error403:
type: object
properties:
error:
type: string
description: "<tt>forbidden</tt> or <tt>invalid_scope</tt>"
error_description:
"$ref": "#/components/schemas/Error/properties/error_description"
Error404:
type: object
properties:
error:
type: string
description: "<tt>not_found</tt>"
error_description:
"$ref": "#/components/schemas/Error/properties/error_description"
Error422:
type: object
properties:
error:
type: string
description: unprocessable entity
error_description:
"$ref": "#/components/schemas/Error/properties/error_description"
securitySchemes: securitySchemes:
oauth2: oauth2:
type: oauth2 type: oauth2