diff --git a/doc/API.md b/doc/API.md
index 2e09cfa4..f295e82f 100644
--- a/doc/API.md
+++ b/doc/API.md
@@ -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
we're open for new additions.
-The API is documented using [Open API 2.0](https://github.com/OAI/OpenAPI-Specification)
-/ [Swagger](https://swagger.io/) in [swagger.v1.yml](swagger.v1.yml).
+The API is documented using [Open API 3.0.1](https://github.com/OAI/OpenAPI-Specification)
+/ [Swagger](https://swagger.io/) in [swagger.yaml](/swagger/v1/swagger.yaml).
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.
diff --git a/spec/requests/api/user_spec.rb b/spec/requests/api/user_spec.rb
new file mode 100644
index 00000000..ed002ba1
--- /dev/null
+++ b/spec/requests/api/user_spec.rb
@@ -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
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
deleted file mode 100644
index d6542fc3..00000000
--- a/spec/requests/api/users_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb
index 504c59c8..c5357e7d 100644
--- a/spec/support/api_helper.rb
+++ b/spec/support/api_helper.rb
@@ -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(:Authorization) { "Bearer #{api_access_token}" }
- # TODO: not needed anymore?
def self.it_handles_invalid_token()
context 'with invalid access token' do
let(:Authorization) { 'abc' }
response 401, 'not logged-in' do
+ schema '$ref' => '#/components/schemas/Error401'
run_test!
end
end
@@ -23,6 +23,7 @@ module ApiHelper
let(:api_scopes) { ['none'] }
response 403, 'missing scope' do
+ schema '$ref' => '#/components/schemas/Error403'
run_test!
end
end
@@ -33,13 +34,4 @@ module ApiHelper
it_handles_invalid_scope(*args)
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
diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb
index 88f0736f..c45fd0af 100644
--- a/spec/swagger_helper.rb
+++ b/spec/swagger_helper.rb
@@ -23,6 +23,69 @@ RSpec.configure do |config|
},
paths: {},
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: 'unauthorized'
+ },
+ error_description: {
+ '$ref': '#/components/schemas/Error/properties/error_description'
+ }
+ }
+ },
+ Error403: {
+ type: :object,
+ properties: {
+ error: {
+ type: :string,
+ description: 'forbidden or invalid_scope'
+ },
+ error_description: {
+ '$ref': '#/components/schemas/Error/properties/error_description'
+ }
+ }
+ },
+ Error404: {
+ type: :object,
+ properties: {
+ error: {
+ type: :string,
+ description: 'not_found'
+ },
+ 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: {
oauth2: {
type: :oauth2,
diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml
index cba34f7e..5fe3a5a3 100644
--- a/swagger/v1/swagger.yaml
+++ b/swagger/v1/swagger.yaml
@@ -12,10 +12,41 @@ paths:
responses:
'200':
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':
description: not logged-in
+ content:
+ application/json:
+ schema:
+ "$ref": "#/components/schemas/Error401"
'403':
description: missing scope
+ content:
+ application/json:
+ schema:
+ "$ref": "#/components/schemas/Error403"
"/user/financial_overview":
get:
summary: financial summary about the currently logged-in user
@@ -25,11 +56,93 @@ paths:
responses:
'200':
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':
description: not logged-in
+ content:
+ application/json:
+ schema:
+ "$ref": "#/components/schemas/Error401"
'403':
description: missing scope
+ content:
+ application/json:
+ schema:
+ "$ref": "#/components/schemas/Error403"
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: "unauthorized"
+ error_description:
+ "$ref": "#/components/schemas/Error/properties/error_description"
+ Error403:
+ type: object
+ properties:
+ error:
+ type: string
+ description: "forbidden or invalid_scope"
+ error_description:
+ "$ref": "#/components/schemas/Error/properties/error_description"
+ Error404:
+ type: object
+ properties:
+ error:
+ type: string
+ description: "not_found"
+ 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:
oauth2:
type: oauth2