Skip to content

Generate swagger inputs automatically #34

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/contracts/application_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require 'dry-validation'

class ApplicationContract < Dry::Validation::Contract
include Supports::ApplicationContract::SwaggerInput

config.messages.backend = :i18n

register_macro(:password_confirmation) do
Expand Down
2 changes: 2 additions & 0 deletions app/contracts/users/passwords/send_instructions_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module Passwords
class SendInstructionsContract < ApplicationContract
params do
required(:email).filled(Types::Email)
required(:client_id).filled(:string)
required(:client_secret).filled(:string)
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions app/contracts/users/passwords/update_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class UpdateContract < ApplicationContract
required(:reset_password_token).filled(:string)
required(:password) { filled? & str? & min_size?(Devise.password_length.min) }
required(:password_confirmation) { filled? & str? & min_size?(Devise.password_length.min) }
required(:client_id).filled(:string)
required(:client_secret).filled(:string)
end

rule(:password).validate(:password_confirmation)
Expand Down
2 changes: 2 additions & 0 deletions app/contracts/users/registrations/register_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class RegisterContract < ApplicationContract
params do
required(:email).filled(Types::Email)
required(:password).filled(:str?, min_size?: Devise.password_length.min)
required(:client_id).filled(:string)
required(:client_secret).filled(:string)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/users/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def update
private

def password_params
params.permit(:email, :reset_password_token, :password, :password_confirmation)
params.permit(:email, :reset_password_token, :password, :password_confirmation, :client_id, :client_secret)
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/users/registrations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def create
private

def registration_params
params.permit(:email, :password)
params.permit(:email, :password, :client_id, :client_secret)
end
end
end
4 changes: 3 additions & 1 deletion app/services/users_service/registrations/register.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def call
private

def create_user
UsersService::Create.new(params:).call
allowed_params = params.except(:client_id, :client_secret)

UsersService::Create.new(params: allowed_params).call
end

def create_access_token(user)
Expand Down
4 changes: 2 additions & 2 deletions app/swagger_docs/controllers/users/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PasswordsController
key :required, true
content :'application/json' do
schema do
key :'$ref', :UserResetPasswordInput
key :'$ref', :UsersPasswordsSendInstructionsContractInput
end
end
end
Expand Down Expand Up @@ -65,7 +65,7 @@ class PasswordsController
key :required, true
content :'application/json' do
schema do
key :'$ref', :UserUpdatePasswordInput
key :'$ref', :UsersPasswordsUpdateContractInput
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RegistrationsController
key :required, true
content :'application/json' do
schema do
key :'$ref', :User#Input
key :'$ref', :UsersRegistrationsRegisterContractInput
end
end
end
Expand Down
30 changes: 0 additions & 30 deletions app/swagger_docs/inputs/user/reset_password_input.rb

This file was deleted.

35 changes: 0 additions & 35 deletions app/swagger_docs/inputs/user/sign_up_input.rb

This file was deleted.

40 changes: 0 additions & 40 deletions app/swagger_docs/inputs/user/update_password_input.rb

This file was deleted.

7 changes: 3 additions & 4 deletions app/swagger_docs/swagger_docs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
class SwaggerDocs
include Swagger::Blocks

CONTACT_CLASSES = ApplicationContract.contract_classes

SWAGGERED_CLASSES = [
## Controllers ##
Controllers::Users::TokensController,
Expand All @@ -13,9 +15,6 @@ class SwaggerDocs
Models::Meta,
## Inputs ##
Inputs::User::SignInInput,
Inputs::User::#Input,
Inputs::User::ResetPasswordInput,
Inputs::User::UpdatePasswordInput,
Inputs::User::RevokeInput,
## Responses ##
Responses::User::SignInResponse,
Expand All @@ -24,7 +23,7 @@ class SwaggerDocs
Responses::User::UpdatePasswordResponse,
Responses::ErrorResponse,
self
].freeze
].concat(CONTACT_CLASSES).freeze

swagger_root do
key :openapi, '3.0.0'
Expand Down
3 changes: 3 additions & 0 deletions config/initializers/dry_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

Dry::Schema.load_extensions(:json_schema)
6 changes: 6 additions & 0 deletions config/locales/contracts/tr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ tr:
params:
email: E-posta
password: Şifre
client_id: 'İstemci kimliği'
client_secret: 'İstemci parolası'
passwords:
updatecontract:
params:
password: Şifre
password_confirmation: Şifre onayı
reset_password_token: Şifre sıfırlama jetonu
client_id: 'İstemci kimliği'
client_secret: 'İstemci parolası'
sendinstructionscontract:
params:
email: E-posta
client_id: 'İstemci kimliği'
client_secret: 'İstemci parolası'
35 changes: 35 additions & 0 deletions docs/SWAGGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,41 @@ end
```
---
### Sample input
All contracts are generating automatically as swagger input components for using easily.

**Auto generated:**

Sample contract:
```ruby
# frozen_string_literal: true

module Users
module Passwords
class SendInstructionsContract < ApplicationContract
params do
required(:email).filled(Types::Email)
required(:client_id).filled(:string)
required(:client_secret).filled(:string)
end
end
end
end
```

You can use just referring name as belowing:
```ruby
request_body do
key :description, 'User credentials'
key :required, true
content :'application/json' do
schema do
key :'$ref', :UsersPasswordsSendInstructionsContractInput
end
end
end
```

**Custom:**
```ruby
# frozen_string_literal: true

Expand Down
52 changes: 52 additions & 0 deletions lib/supports/application_contract/swagger_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

require 'active_support/all'

module Supports
module ApplicationContract
module SwaggerInput
extend ActiveSupport::Concern

module ClassMethods
def _swagger_nodes
{ component_node: OpenStruct.new(data: component_node_data) }
end

def contract_classes
Dir[Rails.root.join('app/contracts/**/*_contract.rb')].map do |path|
klass = path.split('/app/contracts/')
.last
.rpartition('.')
.first
.classify
.constantize

next if klass.eql?(::ApplicationContract)

klass
end.reject(&:blank?)
end

private

def custom_schema_name
"#{name.gsub('::', '')}Input".to_sym
end

def custom_json_schema
json_schema = schema.json_schema(loose: true)

{
type: json_schema[:type],
properties: json_schema[:properties],
required: json_schema[:required]
}
end

def component_node_data
{ schemas: { "#{custom_schema_name}": custom_json_schema } }
end
end
end
end
end