I was wondering if anyone's done this before where they generate API docs using Swagger UI for an API not also generated by Swagger. Here's what a simple example of mine looks like:
class Api::V1::UsersController < Api::V1::BaseController
swagger_controller :users, 'Users'
swagger_api :show do
summary 'Returns a user'
param :path, :id, :integer, :optional, "User Id"
notes '/api/v1/users/:id'
response :ok, "Success", :Users
response :unauthorized
response :not_acceptable
response :not_found
end
def show
user = User.find(params[:id])
render(json: Api::V1::UserSerializer.new(user).to_json)
end
end
I've generated the swagger docs with rake swagger:docs and can reach http://localhost:3000/api-docs.json just fine where I see the documentation for Users#show, but when I click "Try it out!", I get a missing template error for api/v1/users/show
api-docs.json:
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"apis": [
{
"path": "/api/v1/users.{format}",
"description": "Users"
}
],
"authorizations": null
}
users.json:
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"resourcePath": "users",
"apis": [
{
"path": "/api/v1/users/{id}.json",
"operations": [
{
"summary": "Returns a user",
"parameters": [
{
"paramType": "path",
"name": "id",
"type": "integer",
"description": "User Id",
"required": false
}
],
"notes": "/api/v1/users/:id",
"responseMessages": [
{
"code": 200,
"responseModel": "Users",
"message": "Success"
},
{
"code": 401,
"responseModel": null,
"message": "Unauthorized"
},
{
"code": 404,
"responseModel": null,
"message": "Not Found"
},
{
"code": 406,
"responseModel": null,
"message": "Not Acceptable"
}
],
"nickname": "Api::V1::Users#show",
"method": "get"
}
]
}
],
"authorizations": null
}
How can I render the correct response for my show method so that it looks for the serialized json rather than a view file?
So, I found the answer. First, delete all the json files created by rake swagger:docs and add into the swagger_docs.rb initializer the following: :clean_directory => true so that everytime rake swagger:docs is run, the directory in public folder is cleared.
In order for swagger docs to work with how I'm building my API with ActiveModel's Serializers is to change up the DSL written in Api::V1::UsersController, like so:
swagger_api :show do
summary 'Returns a user'
param :path, :id, :integer, :optional, "User Id"
notes '/api/v1/users/:id'
end
then run rake swagger:docs and the call to show a user should work fine.
Related
When I ran following command :
rake swagger:docs
It returns me proper JSON files for each controllers.
When I access swagger-ui, it gives me proper page :
But when I click on Try it Out!, it returns me whole JSON like below :
I am new to Swagger. Can someone please help me out, where am I going wrong ?
UPDATE :
My public directory structure :
UPDATE
trucks.json :
{
"apiVersion": "v1",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"resourcePath": "trucks",
"apis": [
{
"path": "/api/v1/trucks.json",
"operations": [
{
"summary": "Fetches all Trucks",
"parameters": [
{
"paramType": "header",
"name": "X-Auth-Token",
"type": "string",
"description": "Authentication Token",
"required": true
}
],
"responseMessages": [
{
"code": 401,
"responseModel": null,
"message": "Unauthorized"
},
{
"code": 406,
"responseModel": null,
"message": "The request you made is not acceptable"
}
],
"nickname": "API::V1::Trucks#index",
"method": "get"
}
]
}
],
"authorizations": null
}
Figured out the solution. Posting so that if anyone stumbles upon can try it out.
My swagger docs configuration looked like below :
Swagger::Docs::Config.register_apis({
'v1' =>{
:api_extension_type => :json,
:api_file_path => "public",
:base_path => 'http://localhost:3000',
:parent_controller => ApplicationController,
:base_api_controller => ActionController::Base,
:camelize_model_properties => false,
:clean_directory => true,
:attributes => {
:info => {
"title" => "Swagger Yattya",
"description" => "Yattya api documentation",
"termsOfServiceUrl" => "http://helloreverb.com/terms/",
"contact" => "apiteam#wordnik.com",
"license" => "Apache 2.0",
"licenseUrl" => "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
}
})
The first line wasn't required :
:api_extension_type => :json
Removed this line from configuration and worked like a charm!
My swagger index DSL is responding with the api/v1/users.json generated from rake swagger:docs.
Api::V1::UsersController:
swagger_api :index do
summary 'Returns list of users'
notes '/api/v1/users'
end
def index
#users = User.all
render(json: { users: ActiveModel::ArraySerializer.new(#users, each_serializer: Api::V1::UserSerializer) })
end
And when I try go the the actual api documentation and run /api/v1/users.json call ("Try it out!"), I get the public api definition for the whole users api controller:
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"resourcePath": "users",
"apis": [
{
"path": "/api/v1/users.json",
"operations": [
{
"summary": "Returns list of users",
"notes": "/api/v1/users",
"nickname": "Api::V1::Users#index",
"method": "get"
}
]
},
{
"path": "/api/v1/users/{id}.json",
"operations": [
{
"summary": "Returns a user",
"notes": "/api/v1/users/:id",
"parameters": [
{
"paramType": "path",
"name": "id",
"type": "integer",
"description": "User Id",
"required": false
}
],
"nickname": "Api::V1::Users#show",
"method": "get"
}
]
}
],
"authorizations": null
}
Also, when I try the call in Postman, it returns an array of Users like I would expect.
I am using Swagger for the first time and I can't get the details of individual endpoints to show up in the json response within a resource.
Simplified, I have:
# api.rb
require 'grape-swagger'
module API
class Base < Grape::API
version 'v1', using: :path
format :json
resource :items do
desc 'Operations about items'
get '/:id' do
desc 'retrieve data for a single item'
# do something here
end
end
end
In the output, I would expect to see something like:
{
"apiVersion": "0.1",
"swaggerVersion": "1.2",
"produces":
[
"name": "application/json",
],
"resources":
[
{
"name": "items",
"description": "Operations about items",
"apis": [
{
"path": "/items/:id.{format}",
"description": "retrieve data for a single item"
}
]
}
]
}
Instead I get:
{
"apiVersion": "0.1",
"swaggerVersion": "1.2",
"produces":
[
"application/json"
],
"apis":
[
{
"path": "/items.{format}",
"description": "Operations about items"
}
]
}
what am I doing wrong? (using Rails 4.2, Ruby 2.1)
You have to mount the resource first
mount Items
I am documenting the API's of my ROR application using Swagger. This is my initializer file:
class Swagger::Docs::Config
def self.transform_path(path, api_version)
# Make a distinction between the APIs and API documentation paths.
"/apidocs/#{path}"
end
end
Swagger::Docs::Config.register_apis({
'1.0' => {
controller_base_path: '',
api_file_path: 'public/apidocs',
base_path: 'http://localhost:3000',
clean_directory: true
}})
when i run the rake task,the api-docs.json wil generate for swagger GUI.
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000/",
"apis": [
{
"path": "/apidocs/api/v1/users.{format}",
"description": "UserS"
}]}
But the respective JSON generated for users.json,the path is not coming out correctly.
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000/",
"resourcePath": "users",
"apis": [
{
"path": "api/v1/users",
"operations": [
{
"summary": "Fetches all User items",
"notes": "This lists all the active users",
"parameters": [
{.....} ]}]}]}
Instead of "path": "api/v1/users", I need to get "path": "/api/v1/users",
I am using the ActiveRecord Json Validator Gem and I have the following object thats trying to be saved to the model, which should fail, but instead isnt:
[1] pry(#<Api::Internal::V1::UsersController>)> backup
=> #<UserBackup:0x24eddeed
id: nil,
location_name: "test",
user_params: {"user"=>{"user_name"=>"GeorgeLucas", "email"=>"asdsadasdas", "auth_token"=>"jesus"}, "controller"=>"api/internal/v1/users", "action"=>"create"}>
[2] pry(#<Api::Internal::V1::UsersController>)> backup.save!
=> true
As you can see theres a unsaved UserBackup model object in [1] and in [2] is saves, the json in [1] is missing somethig that is set to required: first_name.
The model looks like such:
class UserBackup < ActiveRecord::Base
PROFILE_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'user.json_schema').to_s
validates :location_name, :presence => true
validates :user_params, :presence => true, json: {schema: PROFILE_JSON_SCHEMA}
end
The Json Schema Looks like:
{
"type": "object",
"$schema": "http://json-schema.org/draft-03/schema",
"properties": {
"user": {
"first_name": {
"type": "string",
"required": true
},
"last_name": {
"type": "string",
"required": false
},
"user_name": {
"type": "string",
"required": true
},
"email": {
"type": "string",
"required": true,
"format": "email"
},
"auth_token": {
"type": "string",
"required": true
}
}
}
}
According to my schema, first_name must be a string and it is a required field.
In my json being saved, its missing entirely. Which means that the model should not save the object to the database.
Update One:
Looking at the model object the user_params doesn't look like a json object at all, it looks like a hash of hashes. So with that in mind, here is the controller:
module Api
module Internal
module V1
class UsersController < BaseController
before_action :restrict_api_access
def create
params_json = params.to_json
backup = UserBackup.new(location_name: from_site, user_params: params_json)
binding.pry
if backup.save
return render json: {}, status: 200
else
return render json: {}, status: 422
end
end
end
end
end
end
params_json is indeed a json object:
[3] pry(#<Api::Internal::V1::UsersController>)> params_json
=> "{\"user\":{\"user_name\":\"GeorgeLucas\",\"email\":\"asdsadasdas\",\"auth_token\":\"jesus\"},\"controller\":\"api/internal/v1/users\",\"action\":\"create\"}"
So I am unsure at this point, what exactly is going on.