diff --git a/.rspec b/.rspec new file mode 100644 index 000000000..c99d2e739 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index a0f3aff30..8e571b54d 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,8 @@ ruby '3.2.1' gem 'mysql2', '~> 0.5.5' gem 'puma', '~> 5.0' gem 'rails', '~> 7.0.4', '>= 7.0.4.2' +gem 'rswag-api' +gem 'rswag-ui' # Build JSON APIs with ease [https://github.com/rails/jbuilder] # gem "jbuilder" @@ -32,6 +34,8 @@ group :development, :test do gem 'debug', platforms: %i[mri mingw x64_mingw] gem 'rubocop' gem 'simplecov', require: false, group: :test + gem 'rspec-rails' + gem 'rswag-specs' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 072e9e3dc..428c0f221 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,6 +66,8 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) bcrypt (3.1.18) bootsnap (1.16.0) @@ -75,6 +77,7 @@ GEM crass (1.0.6) date (3.3.3) debug (1.7.1) + diff-lcs (1.5.0) docile (1.4.0) erubi (1.12.0) globalid (1.1.0) @@ -82,6 +85,8 @@ GEM i18n (1.12.0) concurrent-ruby (~> 1.0) json (2.6.3) + json-schema (3.0.0) + addressable (>= 2.8) loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -111,6 +116,7 @@ GEM parallel (1.22.1) parser (3.2.1.0) ast (~> 2.4.1) + public_suffix (5.0.1) puma (5.6.5) nio4r (~> 2.0) racc (1.6.2) @@ -149,6 +155,33 @@ GEM rake (13.0.6) regexp_parser (2.7.0) rexml (3.2.5) + rspec-core (3.12.1) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (6.0.1) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.11) + rspec-expectations (~> 3.11) + rspec-mocks (~> 3.11) + rspec-support (~> 3.11) + rspec-support (3.12.0) + rswag-api (2.8.0) + railties (>= 3.1, < 7.1) + rswag-specs (2.8.0) + activesupport (>= 3.1, < 7.1) + json-schema (>= 2.2, < 4.0) + railties (>= 3.1, < 7.1) + rspec-core (>= 2.14) + rswag-ui (2.8.0) + actionpack (>= 3.1, < 7.1) + railties (>= 3.1, < 7.1) rubocop (1.47.0) json (~> 2.3) parallel (~> 1.10) @@ -190,6 +223,10 @@ DEPENDENCIES puma (~> 5.0) rack-cors rails (~> 7.0.4, >= 7.0.4.2) + rspec-rails + rswag-api + rswag-specs + rswag-ui rubocop simplecov spring diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb new file mode 100644 index 000000000..4d72f6876 --- /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 000000000..0a768c17b --- /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 f2da85c4a..7fc476cff 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' # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/") diff --git a/db/schema.rb b/db/schema.rb index 653803359..52870a282 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,93 +10,93 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 20_230_306_064_753) do - create_table 'assignments', charset: 'utf8mb4', collation: 'utf8mb4_0900_ai_ci', force: :cascade do |t| - t.string 'name' - t.string 'directory_path' - t.integer 'submitter_count' - t.integer 'course_id' - t.integer 'instructor_id' - t.boolean 'private' - t.integer 'num_reviews' - t.integer 'num_review_of_reviews' - t.integer 'num_review_of_reviewers' - t.boolean 'reviews_visible_to_all' - t.integer 'num_reviewers' - t.text 'spec_location' - t.integer 'max_team_size' - t.boolean 'staggered_deadline' - t.boolean 'allow_suggestions' - t.integer 'days_between_submissions' - t.string 'review_assignment_strategy' - t.integer 'max_reviews_per_submission' - t.integer 'review_topic_threshold' - t.boolean 'copy_flag' - t.integer 'rounds_of_reviews' - t.boolean 'microtask' - t.boolean 'require_quiz' - t.integer 'num_quiz_questions' - t.boolean 'is_coding_assignment' - t.boolean 'is_intelligent' - t.boolean 'calculate_penalty' - t.integer 'late_policy_id' - t.boolean 'is_penalty_calculated' - t.integer 'max_bids' - t.boolean 'show_teammate_reviews' - t.boolean 'availability_flag' - t.boolean 'use_bookmark' - t.boolean 'can_review_same_topic' - t.boolean 'can_choose_topic_to_review' - t.boolean 'is_calibrated' - t.boolean 'is_selfreview_enabled' - t.string 'reputation_algorithm' - t.boolean 'is_anonymous' - t.integer 'num_reviews_required' - t.integer 'num_metareviews_required' - t.integer 'num_metareviews_allowed' - t.integer 'num_reviews_allowed' - t.integer 'simicheck' - t.integer 'simicheck_threshold' - t.boolean 'is_answer_tagging_allowed' - t.boolean 'has_badge' - t.boolean 'allow_selecting_additional_reviews_after_1st_round' - t.integer 'sample_assignment_id' - t.datetime 'created_at', null: false - t.datetime 'updated_at', null: false +ActiveRecord::Schema[7.0].define(version: 2023_03_06_064753) do + create_table "assignments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| + t.string "name" + t.string "directory_path" + t.integer "submitter_count" + t.integer "course_id" + t.integer "instructor_id" + t.boolean "private" + t.integer "num_reviews" + t.integer "num_review_of_reviews" + t.integer "num_review_of_reviewers" + t.boolean "reviews_visible_to_all" + t.integer "num_reviewers" + t.text "spec_location" + t.integer "max_team_size" + t.boolean "staggered_deadline" + t.boolean "allow_suggestions" + t.integer "days_between_submissions" + t.string "review_assignment_strategy" + t.integer "max_reviews_per_submission" + t.integer "review_topic_threshold" + t.boolean "copy_flag" + t.integer "rounds_of_reviews" + t.boolean "microtask" + t.boolean "require_quiz" + t.integer "num_quiz_questions" + t.boolean "is_coding_assignment" + t.boolean "is_intelligent" + t.boolean "calculate_penalty" + t.integer "late_policy_id" + t.boolean "is_penalty_calculated" + t.integer "max_bids" + t.boolean "show_teammate_reviews" + t.boolean "availability_flag" + t.boolean "use_bookmark" + t.boolean "can_review_same_topic" + t.boolean "can_choose_topic_to_review" + t.boolean "is_calibrated" + t.boolean "is_selfreview_enabled" + t.string "reputation_algorithm" + t.boolean "is_anonymous" + t.integer "num_reviews_required" + t.integer "num_metareviews_required" + t.integer "num_metareviews_allowed" + t.integer "num_reviews_allowed" + t.integer "simicheck" + t.integer "simicheck_threshold" + t.boolean "is_answer_tagging_allowed" + t.boolean "has_badge" + t.boolean "allow_selecting_additional_reviews_after_1st_round" + t.integer "sample_assignment_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - create_table 'roles', charset: 'utf8mb4', collation: 'utf8mb4_0900_ai_ci', force: :cascade do |t| - t.string 'name' - t.bigint 'parent_id' - t.integer 'default_page_id' - t.datetime 'created_at', null: false - t.datetime 'updated_at', null: false - t.index ['parent_id'], name: 'fk_rails_4404228d2f' + create_table "roles", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| + t.string "name" + t.bigint "parent_id" + t.integer "default_page_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["parent_id"], name: "fk_rails_4404228d2f" end - create_table 'users', charset: 'utf8mb4', collation: 'utf8mb4_0900_ai_ci', force: :cascade do |t| - t.string 'name' - t.string 'password_digest' - t.integer 'role_id' - t.string 'fullname' - t.string 'email' - t.integer 'parent_id' - t.string 'mru_directory_path' - t.boolean 'email_on_review' - t.boolean 'email_on_submission' - t.boolean 'email_on_review_of_review' - t.boolean 'is_new_user' - t.boolean 'master_permission_granted' - t.string 'handle' - t.string 'persistence_token' - t.string 'timezonepref' - t.boolean 'copy_of_emails' - t.integer 'institution_id' - t.boolean 'etc_icons_on_homepage' - t.integer 'locale' - t.datetime 'created_at', null: false - t.datetime 'updated_at', null: false + create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| + t.string "name" + t.string "password_digest" + t.integer "role_id" + t.string "fullname" + t.string "email" + t.integer "parent_id" + t.string "mru_directory_path" + t.boolean "email_on_review" + t.boolean "email_on_submission" + t.boolean "email_on_review_of_review" + t.boolean "is_new_user" + t.boolean "master_permission_granted" + t.string "handle" + t.string "persistence_token" + t.string "timezonepref" + t.boolean "copy_of_emails" + t.integer "institution_id" + t.boolean "etc_icons_on_homepage" + t.integer "locale" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - add_foreign_key 'roles', 'roles', column: 'parent_id', on_delete: :cascade + add_foreign_key "roles", "roles", column: "parent_id", on_delete: :cascade end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 000000000..a53bdba2a --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,63 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require_relative '../config/environment' +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + abort e.to_s.strip +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # You can uncomment this line to turn off ActiveRecord support entirely. + # config.use_active_record = false + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, type: :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/requests/api/v1/roles_spec.rb b/spec/requests/api/v1/roles_spec.rb new file mode 100644 index 000000000..a67a72029 --- /dev/null +++ b/spec/requests/api/v1/roles_spec.rb @@ -0,0 +1,179 @@ +require 'swagger_helper' + +RSpec.describe 'Roles API', type: :request do + + path '/api/v1/roles' do + get('list roles') do + tags 'Roles' + produces 'application/json' + + response(200, 'successful') do + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + + post('create role') do + tags 'Roles' + consumes 'application/json' + parameter name: :role, in: :body, schema: { + type: :object, + properties: { + name: { type: :string }, + parent_id: { type: :integer }, + default_page_id: { type: :integer } + }, + required: [ 'name' ] + } + + response(201, 'Created a role') do + let(:role) { { name: 'Role 1' } } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + + response(422, 'invalid request') do + let(:role) { { name: '' } } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + end + + path '/api/v1/roles/{id}' do + parameter name: 'id', in: :path, type: :integer, description: 'id of the role' + + get('show role') do + tags 'Roles' + response(200, 'successful') do + let(:id) { '123' } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + + patch('update role') do + tags 'Roles' + consumes 'application/json' + parameter name: :role, in: :body, schema: { + type: :object, + properties: { + name: { type: :string }, + parent_id: { type: :integer }, + default_page_id: { type: :integer } + }, + required: [ 'name' ] + } + + response(200, 'successful') do + let(:id) { '123' } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + + response(422, 'invalid request') do + let(:role) { { name: '' } } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + + put('update role') do + tags 'Roles' + consumes 'application/json' + parameter name: :role, in: :body, schema: { + type: :object, + properties: { + name: { type: :string }, + parent_id: { type: :integer }, + default_page_id: { type: :integer } + }, + required: [ 'name' ] + } + + response(200, 'successful') do + let(:id) { '123' } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + + response(422, 'invalid request') do + let(:role) { { name: '' } } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + + delete('delete role') do + tags 'Roles' + response(200, 'successful') do + let(:id) { '123' } + + after do |example| + example.metadata[:response][:content] = { + 'application/json' => { + example: JSON.parse(response.body, symbolize_names: true) + } + } + end + run_test! + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 000000000..a0d408059 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,94 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb new file mode 100644 index 000000000..9deec08d7 --- /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: 'EXPERTIZA API V1', + version: 'v1' + }, + paths: {}, + servers: [ + { + url: 'http://{defaultHost}', + variables: { + defaultHost: { + default: '127.0.0.1:3000' + } + } + } + ] + } + } + + # 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 000000000..234018856 --- /dev/null +++ b/swagger/v1/swagger.yaml @@ -0,0 +1,113 @@ +--- +openapi: 3.0.1 +info: + title: EXPERTIZA API V1 + version: v1 +paths: + "/api/v1/roles": + get: + summary: list roles + tags: + - Roles + responses: + '200': + description: successful + post: + summary: create role + tags: + - Roles + parameters: [] + responses: + '201': + description: Created a role + '422': + description: invalid request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + parent_id: + type: integer + default_page_id: + type: integer + required: + - name + "/api/v1/roles/{id}": + parameters: + - name: id + in: path + description: id of the role + required: true + schema: + type: integer + get: + summary: show role + tags: + - Roles + responses: + '200': + description: successful + patch: + summary: update role + tags: + - Roles + parameters: [] + responses: + '200': + description: successful + '422': + description: invalid request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + parent_id: + type: integer + default_page_id: + type: integer + required: + - name + put: + summary: update role + tags: + - Roles + parameters: [] + responses: + '200': + description: successful + '422': + description: invalid request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + parent_id: + type: integer + default_page_id: + type: integer + required: + - name + delete: + summary: delete role + tags: + - Roles + responses: + '200': + description: successful +servers: +- url: http://{defaultHost} + variables: + defaultHost: + default: 127.0.0.1:3000