mirror of
https://github.com/ditkrg/jsonapi-swagger.git
synced 2026-01-23 14:29:30 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 352fd3da35 | |||
| bee05fea2b | |||
| b301d53f02 | |||
| c7eaef79ab | |||
|
|
8efe5ff488 | ||
|
|
1b01e6a31a | ||
|
|
a0f7422793 | ||
|
|
9eae4f0b0b | ||
|
|
62ceb48307 | ||
|
|
5f7c3b03fa | ||
|
|
4c428d90b9 | ||
|
|
a4c974ab9e | ||
|
|
c24a3eec37 | ||
|
|
157735a266 | ||
|
|
b8e688165b | ||
|
|
f2e93dd395 | ||
|
|
e5fba11472 | ||
|
|
8e32f7dc88 | ||
|
|
1150c75b00 | ||
|
|
288f9f89cd | ||
|
|
a5fe2f7fdc | ||
|
|
3cfe68b421 | ||
|
|
4fa533ea26 | ||
|
|
0ed11cceb0 | ||
|
|
fc51075db7 | ||
|
|
af6f6208ee | ||
|
|
4ca14d7cdf | ||
|
|
17a263a9d1 | ||
|
|
22852dc288 | ||
|
|
390b265522 | ||
|
|
e92d239e47 | ||
|
|
c45c48e0e4 | ||
|
|
9594a49e2c | ||
|
|
e807339d29 | ||
|
|
bd3db5e85e | ||
|
|
5c34d2b57e | ||
|
|
e1d4b7411d | ||
|
|
9cec061bb5 | ||
|
|
2871e78c30 | ||
|
|
c4e3e1d1b3 | ||
|
|
00d8e1d6a1 | ||
|
|
68d5eda6ae |
32
.github/workflows/gempush.yml
vendored
Normal file
32
.github/workflows/gempush.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: jsonapi-swagger
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build + Publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Set up Ruby 2.6
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
version: 2.6.x
|
||||
|
||||
- name: Publish to RubyGems
|
||||
run: |
|
||||
mkdir -p $HOME/.gem
|
||||
touch $HOME/.gem/credentials
|
||||
chmod 0600 $HOME/.gem/credentials
|
||||
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
||||
gem build *.gemspec
|
||||
gem push *.gem
|
||||
env:
|
||||
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
||||
50
README.md
50
README.md
@ -1,6 +1,11 @@
|
||||
# JSONAPI Swagger
|
||||
|
||||
Create a JSONAPI Swagger.
|
||||
Generate JSONAPI Swagger Doc.
|
||||
|
||||
[](https://rubygems.org/gems/jsonapi-swagger)
|
||||
[](https://github.com/superiorlu/jsonapi-swagger/blob/master/LICENSE)
|
||||
|
||||
[](https://i.loli.net/2019/05/05/5ccebf5e782b7.gif)
|
||||
|
||||
## Installation
|
||||
|
||||
@ -20,10 +25,47 @@ Or install it yourself as:
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
rails generate jsonapi:swagger User # UserResponse < JSONAPI::Resource
|
||||
1. config jsonapi swagger
|
||||
```rb
|
||||
# config/initializers/swagger.rb
|
||||
Jsonapi::Swagger.config do |config|
|
||||
config.use_rswag = false
|
||||
config.version = '2.0'
|
||||
config.info = { title: 'API V1', version: 'V1'}
|
||||
config.file_path = 'v1/swagger.json'
|
||||
end
|
||||
```
|
||||
|
||||
2. generate swagger.json
|
||||
|
||||
```sh
|
||||
# gen swagger/v1/swagger.json
|
||||
bundle exec rails generate jsonapi:swagger User # UserResource < JSONAPI::Resource
|
||||
```
|
||||
|
||||
3. additional
|
||||
|
||||
use `rswag`, have to run
|
||||
|
||||
```sh
|
||||
# gen swagger/v1/swagger.json
|
||||
bundle exec rails rswag:specs:swaggerize
|
||||
```
|
||||
|
||||
## RoadMap
|
||||
|
||||
- [x] immutable resources
|
||||
- [x] filter/sort resources
|
||||
- [x] mutable resources
|
||||
- [x] generate swagger.json without rswag
|
||||
|
||||
## Resource
|
||||
|
||||
- [JSONAPI](https://jsonapi.org/)
|
||||
- [JSONAPI::Resources](http://jsonapi-resources.com/)
|
||||
- [Rswag](https://github.com/domaindrivendev/rswag)
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/superiorlu/jsonapi-swagger.
|
||||
Bug reports and pull requests are welcome on GitHub at
|
||||
https://github.com/superiorlu/jsonapi-swagger.
|
||||
|
||||
@ -13,15 +13,6 @@ Gem::Specification.new do |spec|
|
||||
spec.summary = 'JSON API Swagger Doc Generator'
|
||||
spec.homepage = 'https://github.com/superiorlu/jsonapi-swagger'
|
||||
|
||||
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
||||
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
||||
if spec.respond_to?(:metadata)
|
||||
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
||||
else
|
||||
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
||||
'public gem pushes.'
|
||||
end
|
||||
|
||||
# Specify which files should be added to the gem when it is released.
|
||||
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
||||
spec.files = Dir['lib/**/*', 'LICENSE.md', 'README.md']
|
||||
@ -30,8 +21,7 @@ Gem::Specification.new do |spec|
|
||||
spec.licenses = ['MIT']
|
||||
|
||||
spec.add_development_dependency 'bundler', '~> 2.0'
|
||||
spec.add_development_dependency 'rake', '~> 10.0'
|
||||
spec.add_development_dependency 'rake', '>= 12.3.3'
|
||||
spec.add_development_dependency 'rubocop', '~> 0.67'
|
||||
|
||||
spec.add_dependency 'rswag', '~>2.0'
|
||||
spec.add_development_dependency 'rswag', '~>2.0'
|
||||
end
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
Description:
|
||||
Create a JSONAPI Swagger
|
||||
|
||||
Example:
|
||||
rails generate jsonapi:swagger User
|
||||
|
||||
This will create:
|
||||
spec/requests/users_spec.rb
|
||||
@ -4,15 +4,54 @@ module Jsonapi
|
||||
source_root File.expand_path('templates', __dir__)
|
||||
|
||||
def create_swagger_file
|
||||
swagger_file = File.join(
|
||||
if Jsonapi::Swagger.use_rswag
|
||||
template 'swagger.rb.erb', spec_file
|
||||
else
|
||||
template 'swagger.json.erb', json_file
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def doc
|
||||
@doc ||= swagger_json.parse_doc
|
||||
end
|
||||
|
||||
def spec_file
|
||||
@spec_file ||= File.join(
|
||||
'spec/requests',
|
||||
class_path,
|
||||
spec_file_name
|
||||
)
|
||||
template 'swagger.rb.erb', swagger_file
|
||||
end
|
||||
|
||||
private
|
||||
def json_file
|
||||
@json_file ||= File.join(
|
||||
'swagger',
|
||||
class_path,
|
||||
swagger_file_path
|
||||
)
|
||||
end
|
||||
|
||||
def swagger_version
|
||||
Jsonapi::Swagger.version
|
||||
end
|
||||
|
||||
def swagger_info
|
||||
JSON.pretty_generate(Jsonapi::Swagger.info)
|
||||
end
|
||||
|
||||
def swagger_base_path
|
||||
Jsonapi::Swagger.base_path
|
||||
end
|
||||
|
||||
def swagger_file_path
|
||||
Jsonapi::Swagger.file_path
|
||||
end
|
||||
|
||||
def swagger_json
|
||||
@swagger_json ||= Jsonapi::Swagger::Json.new(json_file)
|
||||
end
|
||||
|
||||
def spec_file_name
|
||||
"#{file_name.downcase.pluralize}_spec.rb"
|
||||
@ -34,32 +73,75 @@ module Jsonapi
|
||||
(class_path + [file_name]).map!(&:camelize).join("::")
|
||||
end
|
||||
|
||||
def sortable_fields_desc
|
||||
t(:sortable_fields) + ': (-)' + sortable_fields.join(',')
|
||||
end
|
||||
|
||||
def ori_sortable_fields_desc
|
||||
tt(:sortable_fields) + ': (-)' + sortable_fields.join(',')
|
||||
end
|
||||
|
||||
def model_klass
|
||||
model_class_name.safe_constantize
|
||||
file_name.camelize.safe_constantize
|
||||
end
|
||||
|
||||
def resource_klass
|
||||
"#{model_class_name}Resource".safe_constantize
|
||||
@resource_klass ||= Jsonapi::Swagger::Resource.with(model_class_name)
|
||||
end
|
||||
|
||||
def attributes
|
||||
resource_klass._attributes.except(:id)
|
||||
resource_klass.attributes.except(:id)
|
||||
end
|
||||
|
||||
def relationships
|
||||
resource_klass._relationships
|
||||
resource_klass.relationships
|
||||
end
|
||||
|
||||
def columns_with_comment
|
||||
def sortable_fields
|
||||
resource_klass.sortable_fields
|
||||
end
|
||||
|
||||
def creatable_fields
|
||||
resource_klass.creatable_fields - relationships.keys
|
||||
end
|
||||
|
||||
def updatable_fields
|
||||
resource_klass.updatable_fields - relationships.keys
|
||||
end
|
||||
|
||||
def filters
|
||||
resource_klass.filters
|
||||
end
|
||||
|
||||
def mutable?
|
||||
resource_klass.mutable?
|
||||
end
|
||||
|
||||
def attribute_default
|
||||
Jsonapi::Swagger.attribute_default
|
||||
end
|
||||
|
||||
def transform_method
|
||||
@transform_method ||= resource_klass.transform_method if resource_klass.respond_to?(:transform_method)
|
||||
end
|
||||
|
||||
def columns_with_comment(need_encoding: true)
|
||||
@columns_with_comment ||= {}.tap do |clos|
|
||||
clos.default_proc = proc do |h, k|
|
||||
h[k] = attribute_default
|
||||
end
|
||||
model_klass.columns.each do |col|
|
||||
clos[col.name.to_sym] = { type: swagger_type(col), items_type: col.type, is_array: col.array, nullable: col.null, comment: safe_encode(col.comment) }
|
||||
col_name = transform_method ? col.name.send(transform_method) : col.name
|
||||
is_array = col.respond_to?(:array) ? col.array : false
|
||||
clos[col_name.to_sym] = { type: swagger_type(col), items_type: col.type, is_array: is_array, nullable: col.null, comment: col.comment }
|
||||
clos[col_name.to_sym][:comment] = safe_encode(col.comment) if need_encoding
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def swagger_type(column)
|
||||
return 'array' if column.array
|
||||
return 'array' if column.respond_to?(:array) && column.array
|
||||
|
||||
case column.type
|
||||
when :bigint, :integer then 'integer'
|
||||
when :boolean then 'boolean'
|
||||
@ -67,8 +149,24 @@ module Jsonapi
|
||||
end
|
||||
end
|
||||
|
||||
def safe_encode(comment)
|
||||
comment&.force_encoding('ASCII-8BIT')
|
||||
def relation_table_name(relation)
|
||||
return relation.class_name.tableize if relation.respond_to?(:class_name)
|
||||
return relation.name if relation.respond_to?(:name)
|
||||
end
|
||||
|
||||
def t(key, options={})
|
||||
content = tt(key, options)
|
||||
safe_encode(content)
|
||||
end
|
||||
|
||||
def tt(key, options={})
|
||||
options[:scope] = :jsonapi_swagger
|
||||
options[:default] = key.to_s.humanize
|
||||
I18n.t(key, **options)
|
||||
end
|
||||
|
||||
def safe_encode(content)
|
||||
content&.force_encoding('ASCII-8BIT')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
319
lib/generators/jsonapi/swagger/templates/swagger.json.erb
Normal file
319
lib/generators/jsonapi/swagger/templates/swagger.json.erb
Normal file
@ -0,0 +1,319 @@
|
||||
{
|
||||
"swagger": "<%= swagger_version %>",
|
||||
"info": <%= swagger_info %>,
|
||||
"basePath" : "<%= swagger_base_path %>",
|
||||
<%-
|
||||
def list_resource_parameters
|
||||
[].tap do |parameters|
|
||||
parameters << { name: 'page[number]', in: :query, type: :string, description: tt(:page_num), required: false }
|
||||
parameters << { name: 'page[size]', in: :query, type: :string, description: tt(:page_size), required: false }
|
||||
if sortable_fields.present?
|
||||
parameters << { name: 'sort', in: :query, type: :string, description: ori_sortable_fields_desc, required: false }
|
||||
end
|
||||
if relationships.present?
|
||||
parameters << { name: :include, in: :query, type: :string, description: tt(:include_related_data), required: false }
|
||||
end
|
||||
filters.each do |filter_attr, filter_config|
|
||||
parameters << { name: :"filter[#{filter_attr}]", in: :query, type: :string, description: tt(:filter_field), required: false}
|
||||
end
|
||||
parameters << { name: :"fields[#{route_resouces}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
||||
relationships.each_value do |relation|
|
||||
parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show_resource_parameters
|
||||
[].tap do |parameters|
|
||||
parameters << { name: :id, in: :path, type: :integer, description: 'ID', required: true }
|
||||
if relationships.present?
|
||||
parameters << { name: :include, in: :query, type: :string, description: tt(:include_related_data), required: false }
|
||||
end
|
||||
parameters << { name: :"fields[#{route_resouces}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
||||
relationships.each_value do |relation|
|
||||
parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_resource_parameters
|
||||
parameters = {
|
||||
name: :data,
|
||||
in: :body,
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: route_resouces },
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: properties(attrs: creatable_fields)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
description: tt(:request_body)
|
||||
}
|
||||
parameters[:properties][:data][:properties][:relationships] ||= {}
|
||||
parameters[:properties][:data][:properties][:relationships] = { type: :object, properties: create_relationships_properties }
|
||||
parameters
|
||||
end
|
||||
|
||||
def patch_resource_parameters
|
||||
patch_parameters = create_resource_parameters.dup
|
||||
patch_parameters[:properties][:data][:properties][:id] ||= {}
|
||||
patch_parameters[:properties][:data][:properties][:id].merge!({ type: :integer, description: 'ID' })
|
||||
parameters = [{ name: :id, in: :path, type: :integer, description: 'ID', required: true }]
|
||||
parameters << patch_parameters
|
||||
parameters
|
||||
end
|
||||
|
||||
def delete_resource_parameters
|
||||
[{ name: :id, in: :path, type: :integer, description: 'ID', required: true }]
|
||||
end
|
||||
|
||||
def properties(attrs: [])
|
||||
Hash.new{|h, k| h[k] = {}} .tap do |props|
|
||||
attrs.each do |attr|
|
||||
columns = columns_with_comment(need_encoding: false)
|
||||
props[attr][:type] = columns[attr][:type]
|
||||
props[attr][:items] = { type: columns[attr][:items_type] } if columns[attr][:is_array]
|
||||
props[attr][:'x-nullable'] = columns[attr][:nullable]
|
||||
props[attr][:description] = columns[attr][:comment]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def relationships_properties
|
||||
{}.tap do |relat_props|
|
||||
relationships.each do |relation_name, relation|
|
||||
relation_name_camelize = relation_name.to_s.camelize
|
||||
relat_props[relation_name] = {
|
||||
type: :object,
|
||||
properties: {
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: tt(:associate_list_link, model: relation_name_camelize) },
|
||||
related: { type: :string, description: tt(:related_link, model: relation_name_camelize) },
|
||||
},
|
||||
description: tt(:related_link, model: relation_name_camelize)
|
||||
},
|
||||
},
|
||||
description: tt(:related_model, model: relation_name_camelize)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_relationships_properties
|
||||
{}.tap do |relat_props|
|
||||
relationships.each do |relation_name, relation|
|
||||
relation_name_camelize = relation_name.to_s.camelize
|
||||
relat_props[relation_name] = {
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: relation.table_name },
|
||||
id: { type: :string, description: "#{relation_name_camelize} ID" },
|
||||
},
|
||||
},
|
||||
description: tt(:related_ids, model: relation_name_camelize)
|
||||
}
|
||||
},
|
||||
description: tt(:related_ids, model: relation_name_camelize)
|
||||
}
|
||||
if relation.try(:belongs_to?)
|
||||
relat_props[relation_name][:properties][:data] = {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: relation.table_name },
|
||||
id: { type: :string, description: "#{relation_name_camelize} ID" },
|
||||
},
|
||||
description: tt(:related_id, model: relation_name_camelize)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def list_resource_responses
|
||||
{
|
||||
'200' => {
|
||||
description: tt(:get_list),
|
||||
schema: {
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
properties: {
|
||||
id: { type: :string, description: 'ID'},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: tt(:detail_link) },
|
||||
},
|
||||
description: tt(:detail_link)
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: properties(attrs: attributes.each_key),
|
||||
description: tt(:attributes)
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: relationships_properties,
|
||||
description: tt(:associate_data)
|
||||
}
|
||||
},
|
||||
},
|
||||
description: tt(:data)
|
||||
},
|
||||
meta: {
|
||||
type: :object,
|
||||
properties: {
|
||||
record_count: { type: :integer, description: tt(:record_count)},
|
||||
page_count: { type: :integer, description: tt(:page_count)},
|
||||
},
|
||||
description: tt(:meta)
|
||||
},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
first: { type: :string, description: tt(:first_page_link) },
|
||||
next: { type: :string, description: tt(:next_page_link) },
|
||||
last: { type: :string, description: tt(:last_page_link) },
|
||||
},
|
||||
description: tt(:page_links) },
|
||||
},
|
||||
required: [:data]
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def show_resource_responses
|
||||
{
|
||||
'200' => {
|
||||
description: tt(:get_detail),
|
||||
schema: show_resource_schema
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def create_resource_responses
|
||||
{
|
||||
'201' => {
|
||||
description: tt(:create),
|
||||
schema: show_resource_schema
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def delete_resource_responses
|
||||
{
|
||||
'204' => { description: tt(:delete) }
|
||||
}
|
||||
end
|
||||
|
||||
def show_resource_schema
|
||||
{
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
id: { type: :string, description: 'ID'},
|
||||
type: { type: :string, description: 'Type'},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: tt(:detail_link) },
|
||||
},
|
||||
description: tt(:detail_link)
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: properties(attrs: attributes.each_key),
|
||||
description: tt(:attributes)
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: relationships_properties,
|
||||
description: tt(:associate_data)
|
||||
}
|
||||
},
|
||||
description: tt(:data)
|
||||
}
|
||||
},
|
||||
required: [:data]
|
||||
}
|
||||
end
|
||||
|
||||
doc['paths']["/#{route_resouces}"] = {
|
||||
get: {
|
||||
summary: "#{route_resouces} #{tt(:list)}",
|
||||
tags: [route_resouces],
|
||||
produces: ['application/vnd.api+json'],
|
||||
parameters: list_resource_parameters,
|
||||
responses: list_resource_responses
|
||||
}
|
||||
}
|
||||
|
||||
doc['paths']["/#{route_resouces}/{id}"] = {
|
||||
get: {
|
||||
summary: "#{route_resouces} #{tt(:detail)}",
|
||||
tags: [route_resouces],
|
||||
produces: ['application/vnd.api+json'],
|
||||
parameters: show_resource_parameters,
|
||||
responses: show_resource_responses
|
||||
}
|
||||
}
|
||||
|
||||
if mutable?
|
||||
doc['paths']["/#{route_resouces}"].merge!({
|
||||
post: {
|
||||
summary: "#{route_resouces} #{tt(:create)}",
|
||||
tags: [route_resouces],
|
||||
consumes: ['application/vnd.api+json'],
|
||||
produces: ['application/vnd.api+json'],
|
||||
parameters: [create_resource_parameters],
|
||||
responses: create_resource_responses
|
||||
}
|
||||
})
|
||||
|
||||
doc['paths']["/#{route_resouces}/{id}"].merge!({
|
||||
patch: {
|
||||
summary: "#{route_resouces} #{tt(:patch)}",
|
||||
tags: [route_resouces],
|
||||
consumes: ['application/vnd.api+json'],
|
||||
produces: ['application/vnd.api+json'],
|
||||
parameters: patch_resource_parameters,
|
||||
responses: show_resource_responses
|
||||
}
|
||||
})
|
||||
|
||||
doc['paths']["/#{route_resouces}/{id}"].merge!({
|
||||
delete: {
|
||||
summary: "#{route_resouces} #{tt(:delete)}",
|
||||
tags: [route_resouces],
|
||||
produces: ['application/vnd.api+json'],
|
||||
parameters: delete_resource_parameters,
|
||||
responses: delete_resource_responses
|
||||
}
|
||||
})
|
||||
else
|
||||
doc['paths']["/#{route_resouces}"].delete(:post)
|
||||
doc['paths']["/#{route_resouces}/{id}"].delete(:patch)
|
||||
doc['paths']["/#{route_resouces}/{id}"].delete(:delete)
|
||||
end
|
||||
-%>
|
||||
"paths": <%= JSON.pretty_generate(doc['paths'] ) %>
|
||||
}
|
||||
@ -3,20 +3,32 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
let(:include) {''} #see https://github.com/domaindrivendev/rswag/issues/188
|
||||
|
||||
before(:each) do
|
||||
<% if defined?(FactoryBot) -%>
|
||||
@<%= model_name %> = create :<%= model_name %>
|
||||
<% else -%>
|
||||
@<%= model_name %> = <%= model_class_name %>.create
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
path '/<%= route_resouces %>' do
|
||||
get '<%= route_resouces %>' do
|
||||
get '<%= route_resouces %> <%= t(:list) %>' do
|
||||
tags '<%= route_resouces %>'
|
||||
produces 'application/vnd.api+json'
|
||||
parameter name: :'page[number]', in: :query, type: :string, description: '页码', required: false
|
||||
parameter name: :include, in: :query, type: :string, description: '包含关联数据', required: false
|
||||
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '包含字段', required: false
|
||||
<% relationships.each_key do |relation| -%>
|
||||
parameter name: :'fields[<%= relation.to_s.pluralize %>]', in: :query, type: :string, description: '包含字段', required: false
|
||||
parameter name: :'page[number]', in: :query, type: :string, description: '<%= t(:page_num) %>', required: false
|
||||
<% if sortable_fields.present? -%>
|
||||
parameter name: :'sort', in: :query, type: :string, description: '<%= sortable_fields_desc %>', required: false
|
||||
<% end -%>
|
||||
response '200', '获取列表' do
|
||||
<% if relationships.present? -%>
|
||||
parameter name: :include, in: :query, type: :string, description: '<%= t(:include_related_data) %>', required: false
|
||||
<% end -%>
|
||||
<% filters.each do |filter_attr, filter_config| -%>
|
||||
parameter name: :'filter[<%= filter_attr %>]', in: :query, type: :string, description: '<%= t(:filter_field) %>', <% if filter_config[:default] -%>default: '<%= safe_encode(filter_config[:default]) %>',<% end %>required: false
|
||||
<% end -%>
|
||||
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
||||
<% relationships.each_value do |relation| -%>
|
||||
parameter name: :'fields[<%= relation_table_name(relation) %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
||||
<% end -%>
|
||||
response '200', '<%= t(:get_list) %>' do
|
||||
schema type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
@ -28,18 +40,18 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '详情链接'},
|
||||
self: { type: :string, description: '<%= t(:detail_link) %>'},
|
||||
},
|
||||
description: '详情链接'
|
||||
description: '<%= t(:detail_link) %>'
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% attributes.each_key.each do |attr| -%>
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%> 'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<% end -%>
|
||||
},
|
||||
description: '属性'
|
||||
description: '<%= t(:attributes) %>'
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
@ -52,38 +64,38 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '关联<%= relation_name_camelize %>列表链接' },
|
||||
related: { type: :string, description: '相关<%= relation_name_camelize %>链接' },
|
||||
self: { type: :string, description: '<%= t(:associate_list_link, model: relation_name_camelize) %>' },
|
||||
related: { type: :string, description: '<%= t(:related_link, model: relation_name_camelize) %>' },
|
||||
},
|
||||
description: '相关的<%= relation_name_camelize %>链接'
|
||||
description: '<%= t(:related_link, model: relation_name_camelize)%>'
|
||||
},
|
||||
},
|
||||
description: '相关<%= relation_name_camelize %>'
|
||||
description: '<%= t(:related_model, model: relation_name_camelize)%>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '关联数据'
|
||||
description: '<%= t(:associate_data) %>'
|
||||
}
|
||||
},
|
||||
},
|
||||
description: '数据'
|
||||
description: '<%= t(:data) %>'
|
||||
},
|
||||
meta: {
|
||||
type: :object,
|
||||
properties: {
|
||||
record_count: { type: :integer, description: '总记录数'},
|
||||
page_count: { type: :integer, description: '页数'},
|
||||
record_count: { type: :integer, description: '<%= t(:record_count) %>'},
|
||||
page_count: { type: :integer, description: '<%= t(:page_count) %>'},
|
||||
},
|
||||
description: '分页记录数'
|
||||
description: '<%= t(:meta) %>'
|
||||
},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
first: { type: :string, description: '第一页'},
|
||||
next: { type: :string, description: '下一页'},
|
||||
last: { type: :string, description: '最后一页'},
|
||||
first: { type: :string, description: '<%= t(:first_page_link) %>'},
|
||||
next: { type: :string, description: '<%= t(:next_page_link) %>'},
|
||||
last: { type: :string, description: '<%= t(:last_page_link) %>'},
|
||||
},
|
||||
description: '分页链接' },
|
||||
description: '<%= t(:page_links) %>' },
|
||||
},
|
||||
required: [:data]
|
||||
run_test!
|
||||
@ -92,16 +104,18 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
end
|
||||
|
||||
path '/<%= route_resouces %>/{id}' do
|
||||
get '<%= route_resouces %>详情' do
|
||||
get '<%= route_resouces %> <%= t(:detail) %>' do
|
||||
tags '<%= route_resouces %>'
|
||||
produces 'application/vnd.api+json'
|
||||
parameter name: :id, in: :path, type: :integer, description: 'ID', required: true
|
||||
parameter name: :include, in: :query, type: :string, description: '包含关联数据', required: false
|
||||
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '包含字段', required: false
|
||||
<% relationships.each_key do |relation| -%>
|
||||
parameter name: :'fields[<%= relation.to_s.pluralize %>]', in: :query, type: :string, description: '包含字段', required: false
|
||||
<% if relationships.present? -%>
|
||||
parameter name: :include, in: :query, type: :string, description: '<%= t(:include_related_data) %>', required: false
|
||||
<% end -%>
|
||||
response '200', '获取详情' do
|
||||
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
||||
<% relationships.each_value do |relation| -%>
|
||||
parameter name: :'fields[<%= relation_table_name(relation) %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
||||
<% end -%>
|
||||
response '200', '<%= t(:get_detail) %>' do
|
||||
schema type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
@ -112,18 +126,18 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '详情链接'},
|
||||
self: { type: :string, description: '<%= t(:detail_link) %>'},
|
||||
},
|
||||
description: '详情链接'
|
||||
description: '<%= t(:detail_link) %>'
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% attributes.each_key.each do |attr| -%>
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%> 'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<% end -%>
|
||||
},
|
||||
description: '属性'
|
||||
description: '<%= t(:attributes) %>'
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
@ -136,20 +150,20 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '关联<%= relation_name_camelize %>列表链接' },
|
||||
related: { type: :string, description: '相关<%= relation_name_camelize %>链接' },
|
||||
self: { type: :string, description: '<%= t(:associate_list_link, model: relation_name_camelize) %>' },
|
||||
related: { type: :string, description: '<%= t(:related_link, model: relation_name_camelize )%>' },
|
||||
},
|
||||
description: '相关的<%= relation_name_camelize %>链接'
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
},
|
||||
description: '相关<%= relation_name_camelize %>'
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '关联数据'
|
||||
description: '<%= t(:associate_data) %>'
|
||||
}
|
||||
},
|
||||
description: '数据'
|
||||
description: '<%= t(:data) %>'
|
||||
},
|
||||
},
|
||||
required: [:data]
|
||||
@ -158,6 +172,264 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
||||
end
|
||||
end
|
||||
end
|
||||
<% unless resource_klass.immutable -%>
|
||||
|
||||
<% if mutable? -%>
|
||||
path '/<%= route_resouces %>' do
|
||||
post '<%= route_resouces %> <%= t(:create) %>' do
|
||||
tags '<%= route_resouces %>'
|
||||
consumes 'application/vnd.api+json'
|
||||
produces 'application/vnd.api+json'
|
||||
parameter name: :data,
|
||||
in: :body,
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= route_resouces %>' },
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% creatable_fields.each do |field| -%>
|
||||
<%= field %>: { type: :<%= columns_with_comment[field][:type] %>, <%if columns_with_comment[field][:is_array] -%> items: { type: :<%= columns_with_comment[field][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[field][:nullable] %>, description: '<%= columns_with_comment[field][:comment] %>'},
|
||||
<% end -%>
|
||||
}
|
||||
},
|
||||
<% if relationships.present? -%>
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% relationships.each do |relation_name, relation| -%>
|
||||
<% relation_name_camelize = relation_name.to_s.camelize -%>
|
||||
<%= relation_name %>: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% if relation.try(:belongs_to?) -%>
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= relation.table_name %>' },
|
||||
id: { type: :string, description: '<%= relation_name_camelize %> ID' },
|
||||
},
|
||||
description: '<%= t(:related_id, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% else -%>
|
||||
data: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= relation.table_name %>' },
|
||||
id: { type: :string, description: '<%= relation_name_camelize %> ID' },
|
||||
},
|
||||
},
|
||||
description: '<%= t(:related_ids, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:related_ids, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
}
|
||||
}
|
||||
<% end -%>
|
||||
}
|
||||
},
|
||||
},
|
||||
description: '<%= t(:request_body) %>'
|
||||
|
||||
response '201', '<%= t(:create) %>' do
|
||||
schema type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
id: { type: :string, description: 'ID'},
|
||||
type: { type: :string, description: 'Type'},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '<%= t(:detail_link) %>'},
|
||||
},
|
||||
description: '<%= t(:detail_link) %>'
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% attributes.each_key.each do |attr| -%>
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:attributes) %>'
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% relationships.each do |relation_name, relation| -%>
|
||||
<% relation_name_camelize = relation_name.to_s.camelize -%>
|
||||
<%= relation_name %>: {
|
||||
type: :object,
|
||||
properties: {
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '<%= t(:associate_list_link, model: relation_name_camelize) %>' },
|
||||
related: { type: :string, description: '<%= t(:related_link, model: relation_name_camelize )%>' },
|
||||
},
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
},
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:associate_data) %>'
|
||||
}
|
||||
},
|
||||
description: '<%= t(:data) %>'
|
||||
},
|
||||
},
|
||||
required: [:data]
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path '/<%= route_resouces %>/{id}' do
|
||||
patch '<%= route_resouces %> <%= t(:patch) %>' do
|
||||
tags '<%= route_resouces %>'
|
||||
consumes 'application/vnd.api+json'
|
||||
produces 'application/vnd.api+json'
|
||||
parameter name: :id, in: :path, type: :integer, description: 'ID', required: true
|
||||
parameter name: :data,
|
||||
in: :body,
|
||||
type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= route_resouces %>' },
|
||||
id: { type: :string },
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% creatable_fields.each do |field| -%>
|
||||
<%= field %>: { type: :<%= columns_with_comment[field][:type] %>, <%if columns_with_comment[field][:is_array] -%> items: { type: :<%= columns_with_comment[field][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[field][:nullable] %>, description: '<%= columns_with_comment[field][:comment] %>'},
|
||||
<% end -%>
|
||||
}
|
||||
},
|
||||
<% if relationships.present? -%>
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% relationships.each do |relation_name, relation| -%>
|
||||
<% relation_name_camelize = relation_name.to_s.camelize -%>
|
||||
<%= relation_name %>: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% if relation.belongs_to? -%>
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= relation.table_name %>' },
|
||||
id: { type: :string, description: '<%= relation_name_camelize %> ID' },
|
||||
},
|
||||
description: '<%= t(:related_id, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% else -%>
|
||||
data: {
|
||||
type: :array,
|
||||
items: {
|
||||
type: :object,
|
||||
properties: {
|
||||
type: { type: :string, default: '<%= relation.table_name %>' },
|
||||
id: { type: :string, description: '<%= relation_name_camelize %> ID' },
|
||||
},
|
||||
},
|
||||
description: '<%= t(:related_ids, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:related_ids, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
}
|
||||
}
|
||||
<% end -%>
|
||||
}
|
||||
},
|
||||
},
|
||||
description: '<%= t(:request_body) %>'
|
||||
|
||||
response '200', '<%= t(:patch) %>' do
|
||||
schema type: :object,
|
||||
properties: {
|
||||
data: {
|
||||
type: :object,
|
||||
properties: {
|
||||
id: { type: :string, description: 'ID'},
|
||||
type: { type: :string, description: 'Type'},
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '<%= t(:detail_link) %>'},
|
||||
},
|
||||
description: '<%= t(:detail_link) %>'
|
||||
},
|
||||
attributes: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% attributes.each_key.each do |attr| -%>
|
||||
<%= attr %>: { type: :<%= columns_with_comment[attr][:type] %>, <%if columns_with_comment[attr][:is_array] -%> items: { type: :<%= columns_with_comment[attr][:items_type] %>},<% end -%>'x-nullable': <%= columns_with_comment[attr][:nullable] %>, description: '<%= columns_with_comment[attr][:comment] %>'},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:attributes) %>'
|
||||
},
|
||||
relationships: {
|
||||
type: :object,
|
||||
properties: {
|
||||
<% relationships.each do |relation_name, relation| -%>
|
||||
<% relation_name_camelize = relation_name.to_s.camelize -%>
|
||||
<%= relation_name %>: {
|
||||
type: :object,
|
||||
properties: {
|
||||
links: {
|
||||
type: :object,
|
||||
properties: {
|
||||
self: { type: :string, description: '<%= t(:associate_list_link, model: relation_name_camelize) %>' },
|
||||
related: { type: :string, description: '<%= t(:related_link, model: relation_name_camelize )%>' },
|
||||
},
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
},
|
||||
description: '<%= t(:related_link, model: relation_name_camelize) %>'
|
||||
},
|
||||
<% end -%>
|
||||
},
|
||||
description: '<%= t(:associate_data) %>'
|
||||
}
|
||||
},
|
||||
description: '<%= t(:data) %>'
|
||||
},
|
||||
},
|
||||
required: [:data]
|
||||
let(:id) { @<%= model_name %>.id }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path '/<%= route_resouces %>/{id}' do
|
||||
delete '<%= route_resouces %> <%= t(:delete) %>' do
|
||||
tags '<%= route_resouces %>'
|
||||
produces 'application/vnd.api+json'
|
||||
parameter name: :id, in: :path, type: :integer, description: 'ID', required: true
|
||||
|
||||
response '204', '<%= t(:delete) %>' do
|
||||
let(:id) { @<%= model_name %>.id }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
33
lib/i18n/en.yml
Normal file
33
lib/i18n/en.yml
Normal file
@ -0,0 +1,33 @@
|
||||
en:
|
||||
jsonapi_swagger:
|
||||
page_num: 'Page Number'
|
||||
page_size: 'Page Size'
|
||||
include_related_data: 'Include Related Data'
|
||||
sortable_fields: 'Sortable Fields'
|
||||
display_field: 'Display Field'
|
||||
filter_field: 'Filter Field'
|
||||
list: 'List'
|
||||
get_list: 'Fetch List'
|
||||
detail_link: 'Detail Link'
|
||||
attributes: 'Attributes'
|
||||
associate_list_link: 'Associate to %{model} Link'
|
||||
related_link: 'Related %{model} Link'
|
||||
related_model: 'Related %{model}'
|
||||
associate_data: 'Associate to Date'
|
||||
data: 'Data'
|
||||
record_count: 'Total Record Count'
|
||||
page_count: 'Page Count'
|
||||
meta: 'Meta'
|
||||
first_page_link: 'First Page'
|
||||
next_page_link: 'Next Page'
|
||||
last_page_link: 'Last Page'
|
||||
page_links: 'Page Link'
|
||||
detail: 'Detail'
|
||||
get_dtail: 'Fetch Detail'
|
||||
detail_link: 'Detail Link'
|
||||
create: 'Create'
|
||||
patch: 'Patch'
|
||||
delete: 'Delete'
|
||||
related_id: 'Related %{model} ID'
|
||||
related_ids: 'Related %{model} IDs'
|
||||
request_body: 'Request Body'
|
||||
33
lib/i18n/zh-CN.yml
Normal file
33
lib/i18n/zh-CN.yml
Normal file
@ -0,0 +1,33 @@
|
||||
zh-CN:
|
||||
jsonapi_swagger:
|
||||
page_num: '页码'
|
||||
page_size: '每页条数'
|
||||
include_related_data: '包含关联数据'
|
||||
sortable_fields: '排序字段'
|
||||
display_field: '显示字段'
|
||||
filter_field: '过滤字段'
|
||||
list: '列表'
|
||||
get_list: '获取列表'
|
||||
detail_link: '详情链接'
|
||||
attributes: '属性'
|
||||
associate_list_link: '关联%{model}链接'
|
||||
related_link: '相关%{model}链接'
|
||||
related_model: '相关%{model}'
|
||||
associate_data: '关联数据'
|
||||
data: '数据'
|
||||
record_count: '总记录数'
|
||||
page_count: '页数'
|
||||
meta: '元数据'
|
||||
first_page_link: '第一页链接'
|
||||
next_page_link: '下一页链接'
|
||||
last_page_link: '最后一页链接'
|
||||
page_links: '分页链接'
|
||||
detail: '详情'
|
||||
get_dtail: '获取详情'
|
||||
detail_link: '详情链接'
|
||||
create: '创建'
|
||||
patch: '更新'
|
||||
delete: '删除'
|
||||
related_id: '相关%{model}ID'
|
||||
related_ids: '相关%{model}IDs'
|
||||
request_body: '请求body'
|
||||
@ -1,10 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'jsonapi/swagger/version'
|
||||
require 'jsonapi/swagger/railtie' if defined?(Rails)
|
||||
require 'jsonapi/swagger/json'
|
||||
require 'jsonapi/swagger/resource'
|
||||
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class Error < StandardError; end
|
||||
# Your code goes here...
|
||||
|
||||
class << self
|
||||
attr_accessor :version, :info, :file_path, :base_path, :use_rswag
|
||||
|
||||
def config
|
||||
yield self
|
||||
end
|
||||
|
||||
def version
|
||||
@version ||= '2.0'
|
||||
end
|
||||
|
||||
def info
|
||||
@info ||= { title: 'API V1', version: 'V1' }
|
||||
end
|
||||
|
||||
def file_path
|
||||
@file_path ||= 'v1/swagger.json'
|
||||
end
|
||||
|
||||
def base_path
|
||||
@base_path
|
||||
end
|
||||
|
||||
def use_rswag
|
||||
@use_rswag ||= false
|
||||
end
|
||||
|
||||
def attribute_default
|
||||
@attribute_default ||= { type: :string, nullable: true, comment: nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
31
lib/jsonapi/swagger/json.rb
Normal file
31
lib/jsonapi/swagger/json.rb
Normal file
@ -0,0 +1,31 @@
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class Json
|
||||
|
||||
attr_accessor :path
|
||||
|
||||
def initialize(path = 'swagger/v1/swagger.json')
|
||||
@path = path
|
||||
end
|
||||
|
||||
def parse_doc
|
||||
@doc ||= JSON.parse(load) rescue Hash.new{ |h, k| h[k]= {} }
|
||||
end
|
||||
|
||||
def base_path
|
||||
Jsonapi::Swagger.base_path
|
||||
end
|
||||
|
||||
def load
|
||||
@data ||= if File.exist?(path)
|
||||
IO.read(path)
|
||||
else
|
||||
puts "create swagger.json in #{path}"
|
||||
'{}'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
16
lib/jsonapi/swagger/railtie.rb
Normal file
16
lib/jsonapi/swagger/railtie.rb
Normal file
@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class Railtie < ::Rails::Railtie
|
||||
initializer 'jsonapi-swagger-i18n' do |app|
|
||||
locates = app.config.i18n.available_locales
|
||||
locates_dir = File.expand_path('../../i18n', __dir__)
|
||||
Array(locates).each do |loc|
|
||||
locate_file = File.join(locates_dir, "#{loc}.yml")
|
||||
I18n.load_path.push(locate_file) if File.exist?(locate_file) && !I18n.load_path.include?(locate_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
lib/jsonapi/swagger/resource.rb
Normal file
15
lib/jsonapi/swagger/resource.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require 'forwardable'
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class Resource
|
||||
def self.with(model_class_name)
|
||||
@resource_class = model_class_name.safe_constantize
|
||||
unless @resource_class < JSONAPI::Serializable::Resource
|
||||
raise Jsonapi::Swagger::Error, "#{@resource_class.class} is not Subclass of JSONAPI::Serializable::Resource!"
|
||||
end
|
||||
require 'jsonapi/swagger/resources/serializable_resource'
|
||||
return Jsonapi::Swagger::SerializableResource.new(@resource_class)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
lib/jsonapi/swagger/resources/fast_jsonapi_resource.rb
Normal file
39
lib/jsonapi/swagger/resources/fast_jsonapi_resource.rb
Normal file
@ -0,0 +1,39 @@
|
||||
require 'forwardable'
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class FastJsonapiResource
|
||||
extend Forwardable
|
||||
|
||||
def_delegators :@fr, :attributes_to_serialize, :relationships_to_serialize, :sortable_fields,
|
||||
:creatable_fields, :updatable_fields, :filters, :mutable?, :transform_method
|
||||
|
||||
def initialize(fr)
|
||||
@fr = fr
|
||||
end
|
||||
|
||||
alias attributes attributes_to_serialize
|
||||
alias relationships relationships_to_serialize
|
||||
|
||||
# TODO: fast_jsonapi resource
|
||||
def sortable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def creatable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def updatable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def filters
|
||||
[]
|
||||
end
|
||||
|
||||
def mutable?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
18
lib/jsonapi/swagger/resources/jsonapi_resource.rb
Normal file
18
lib/jsonapi/swagger/resources/jsonapi_resource.rb
Normal file
@ -0,0 +1,18 @@
|
||||
require 'forwardable'
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class JsonapiResource
|
||||
extend Forwardable
|
||||
|
||||
def_delegators :@jr, :_attributes, :_relationships, :sortable_fields,
|
||||
:creatable_fields, :updatable_fields, :filters, :mutable?
|
||||
|
||||
def initialize(jr)
|
||||
@jr = jr
|
||||
end
|
||||
|
||||
alias attributes _attributes
|
||||
alias relationships _relationships
|
||||
end
|
||||
end
|
||||
end
|
||||
45
lib/jsonapi/swagger/resources/serializable_resource.rb
Normal file
45
lib/jsonapi/swagger/resources/serializable_resource.rb
Normal file
@ -0,0 +1,45 @@
|
||||
require 'forwardable'
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
class SerializableResource
|
||||
extend Forwardable
|
||||
|
||||
def_delegators :@sr, :type_val, :attribute_blocks, :relationship_blocks, :link_blocks
|
||||
|
||||
def initialize(sr)
|
||||
@sr = sr
|
||||
end
|
||||
|
||||
alias attributes attribute_blocks
|
||||
|
||||
def relationships
|
||||
{}.tap do |relations|
|
||||
relationship_blocks.each do |rel, block|
|
||||
relations[rel] = OpenStruct.new(class_name: rel.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: from jsonapi serializable resource
|
||||
def sortable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def creatable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def updatable_fields
|
||||
[]
|
||||
end
|
||||
|
||||
def filters
|
||||
[]
|
||||
end
|
||||
|
||||
def mutable?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
module Jsonapi
|
||||
module Swagger
|
||||
VERSION = '0.2.0'
|
||||
VERSION = '0.8.3'
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user