diff --git a/lib/generators/jsonapi/swagger/swagger_generator.rb b/lib/generators/jsonapi/swagger/swagger_generator.rb index ddc9e4a..daf6417 100644 --- a/lib/generators/jsonapi/swagger/swagger_generator.rb +++ b/lib/generators/jsonapi/swagger/swagger_generator.rb @@ -41,10 +41,18 @@ def swagger_info JSON.pretty_generate(Jsonapi::Swagger.info) end + def swagger_host + Jsonapi::Swagger.host + end + def swagger_base_path Jsonapi::Swagger.base_path end + def swagger_security_definitions + JSON.pretty_generate(Jsonapi::Swagger.security_definitions) + end + def swagger_file_path Jsonapi::Swagger.file_path end @@ -66,11 +74,11 @@ def resouces_name end def route_resouces - resouces_name.tableize + resouces_name.tableize.dasherize end def model_class_name - (class_path + [file_name]).map!(&:camelize).join("::") + (class_path + [file_name]).map!(&:camelize).join('::') end def sortable_fields_desc @@ -133,7 +141,7 @@ def columns_with_comment(need_encoding: true) model_klass.columns.each do |col| 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] = { 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 @@ -154,12 +162,12 @@ def relation_table_name(relation) return relation.name if relation.respond_to?(:name) end - def t(key, options={}) + def t(key, options = {}) content = tt(key, options) safe_encode(content) end - def tt(key, options={}) + def tt(key, options = {}) options[:scope] = :jsonapi_swagger options[:default] = key.to_s.humanize I18n.t(key, options) diff --git a/lib/generators/jsonapi/swagger/templates/swagger.json.erb b/lib/generators/jsonapi/swagger/templates/swagger.json.erb index 6793887..5fd0360 100644 --- a/lib/generators/jsonapi/swagger/templates/swagger.json.erb +++ b/lib/generators/jsonapi/swagger/templates/swagger.json.erb @@ -1,7 +1,9 @@ { "swagger": "<%= swagger_version %>", "info": <%= swagger_info %>, + "host": "<%= swagger_host %>", "basePath" : "<%= swagger_base_path %>", + "securityDefinitions": <%= swagger_security_definitions %>, <%- def list_resource_parameters [].tap do |parameters| @@ -20,10 +22,14 @@ relationships.each_value do |relation| parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false } end + duplicate = parameters.detect{ |el| parameters.count(el) > 1 } + if duplicate + parameters.delete_at(parameters.find_index(duplicate)) + end end end - def show_resource_parameters + def detail_resource_parameters [].tap do |parameters| parameters << { name: :id, in: :path, type: :integer, description: 'ID', required: true } if relationships.present? @@ -33,6 +39,10 @@ relationships.each_value do |relation| parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false } end + duplicate = parameters.detect{ |el| parameters.count(el) > 1 } + if duplicate + parameters.delete_at(parameters.find_index(duplicate)) + end end end @@ -40,30 +50,31 @@ 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) + schema: { + 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[:schema][:properties][:data][:properties][:relationships] ||= {} + parameters[:schema][: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' }) + patch_parameters[:schema][:properties][:data][:properties][:id] ||= {} + patch_parameters[:schema][:properties][:data][:properties][:id].merge!({ type: :integer, description: 'ID' }) parameters = [{ name: :id, in: :path, type: :integer, description: 'ID', required: true }] parameters << patch_parameters parameters @@ -76,11 +87,13 @@ 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] + # We dasherize the attribute key because JSONApiResources needs attributes to be dasherized + dasherizedAttr = attr.to_s.gsub("_", "-") + columns = columns_with_comment(need_encoding: false) + props[dasherizedAttr][:type] = columns[attr][:type] + props[dasherizedAttr][:items] = { type: columns[attr][:items_type] } if columns[attr][:is_array] + props[dasherizedAttr][:'x-nullable'] = columns[attr][:nullable] + props[dasherizedAttr][:description] = columns[attr][:comment] || '' end end end @@ -199,7 +212,7 @@ } end - def show_resource_responses + def detail_resource_responses { '200' => { description: tt(:get_detail), @@ -208,6 +221,8 @@ } end + alias patch_resource_responses detail_resource_responses + def create_resource_responses { '201' => { @@ -257,63 +272,53 @@ } 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 - } - } + current_resource = file_name.pluralize + id = ActiveRecord::Base.connection.exec_query("SELECT id FROM #{current_resource} LIMIT 1").to_a[0]["id"] + + doc['paths']["/#{route_resouces}"] = {} + doc['paths']["/#{route_resouces}/{id}"] = {} + + [:list, :detail, :create, :patch, :delete].each do |action| + method = action + if action == :list || action == :detail + method = :get + elsif action == :create + method = :post + end - doc['paths']["/#{route_resouces}/{id}"] = { - get: { - summary: "#{route_resouces} #{tt(:detail)}", + path_hash = Hash.new + path_hash[method] = { + summary: "#{route_resouces} #{tt(action)}", tags: [route_resouces], + consumes: ['application/vnd.api+json'], produces: ['application/vnd.api+json'], - parameters: show_resource_parameters, - responses: show_resource_responses + security: [{ BasicAuth: [] }], + parameters: send("#{action.to_s}_resource_parameters"), + responses: send("#{action.to_s}_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 - } - }) + if action == :create + path_hash[method][:parameters] = [path_hash[method][:parameters]] + end - 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 - } - }) + if action == :list || action == :create + if Rails.application.routes.recognize_path("#{route_resouces}", method: method)[:action] != 'error' + doc['paths']["/#{route_resouces}"].merge!(path_hash) + end + else + if Rails.application.routes.recognize_path("#{route_resouces}/#{id}", method: method)[:action] != 'error' + doc['paths']["/#{route_resouces}/{id}"].merge!(path_hash) + end + end + end - 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 --%> + if doc['paths']["/#{route_resouces}"] == {} + doc['paths'].delete("/#{route_resouces}") + end + + if doc['paths']["/#{route_resouces}/{id}"] == {} + doc['paths'].delete("/#{route_resouces}/{id}") + end + -%> "paths": <%= JSON.pretty_generate(doc['paths'] ) %> } \ No newline at end of file diff --git a/lib/jsonapi/swagger.rb b/lib/jsonapi/swagger.rb index 9c0c689..5e4d503 100644 --- a/lib/jsonapi/swagger.rb +++ b/lib/jsonapi/swagger.rb @@ -10,7 +10,7 @@ module Swagger class Error < StandardError; end class << self - attr_accessor :version, :info, :file_path, :base_path, :use_rswag + attr_accessor :version, :info, :file_path, :base_path, :host, :use_rswag def config yield self @@ -32,6 +32,14 @@ def base_path @base_path end + def host + @host + end + + def security_definitions + @security_definitions ||= { BasicAuth: { type: 'basic' } } + end + def use_rswag @use_rswag ||= false end diff --git a/lib/jsonapi/swagger/json.rb b/lib/jsonapi/swagger/json.rb index b23c3e9..ce0b17b 100644 --- a/lib/jsonapi/swagger/json.rb +++ b/lib/jsonapi/swagger/json.rb @@ -12,6 +12,10 @@ def parse_doc @doc ||= JSON.parse(load) rescue Hash.new{ |h, k| h[k]= {} } end + def host + Jsonapi::Swagger.host + end + def base_path Jsonapi::Swagger.base_path end