From 8e288dc4ba346546c091b64d6f8596b1a87384e6 Mon Sep 17 00:00:00 2001 From: Michel Felipe de Oliveira Ferreira Date: Tue, 1 Sep 2015 08:22:55 -0300 Subject: [PATCH] Added swagger-ui support to Grape API documentation and request runner --- Gemfile | 4 ++++ app/controllers/api_docs_controller.rb | 8 ++++++++ app/views/api_docs/index.html.erb | 1 + app/views/layouts/api_docs.html.erb | 14 ++++++++++++++ config/routes.rb | 1 + lib/noosfero/api/api.rb | 2 ++ lib/noosfero/api/entities.rb | 13 +++++++------ lib/noosfero/api/v1/articles.rb | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 8 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 app/controllers/api_docs_controller.rb create mode 100644 app/views/api_docs/index.html.erb create mode 100644 app/views/layouts/api_docs.html.erb diff --git a/Gemfile b/Gemfile index 4753856..88ece7d 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,10 @@ gem 'eita-jrails', '~> 0.9.5', require: 'jrails' # API dependencies gem 'grape', '~> 0.12' gem 'grape-entity' +gem 'grape-swagger' +gem 'swagger-ui_rails' +gem 'kramdown' + #FIXME Get the Grape Loggin from master yo solve this issue https://github.com/intridea/grape/issues/1059 #We have to remove this commit referenve code when update the next release of grape_logging. Actualy we are using (1.1.2) gem 'grape_logging', :git => 'https://github.com/aceunreal/grape_logging.git', :ref => 'f1755ae' diff --git a/app/controllers/api_docs_controller.rb b/app/controllers/api_docs_controller.rb new file mode 100644 index 0000000..3464314 --- /dev/null +++ b/app/controllers/api_docs_controller.rb @@ -0,0 +1,8 @@ +class ApiDocsController < ApplicationController + layout :api_layout + + private + def api_layout + params[:controller] + end +end diff --git a/app/views/api_docs/index.html.erb b/app/views/api_docs/index.html.erb new file mode 100644 index 0000000..9e67f55 --- /dev/null +++ b/app/views/api_docs/index.html.erb @@ -0,0 +1 @@ +<%= render 'swagger_ui/swagger_ui', discovery_url: '/api/v1/api_docs' %> diff --git a/app/views/layouts/api_docs.html.erb b/app/views/layouts/api_docs.html.erb new file mode 100644 index 0000000..d594591 --- /dev/null +++ b/app/views/layouts/api_docs.html.erb @@ -0,0 +1,14 @@ + + + + + + <%= stylesheet_link_tag 'swagger-ui' %> + <%= javascript_include_tag 'swagger-ui' %> + + +
+ <%= yield %> +
+ + diff --git a/config/routes.rb b/config/routes.rb index 1aae0d4..c329f43 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,7 @@ Noosfero::Application.routes.draw do match 'site(/:action)', :controller => 'home' match 'api(/:action)', :controller => 'api' + match 'api_docs(/:action)', :controller => 'api_docs' match 'images(/*stuff)' => 'not_found#nothing' match 'stylesheets(/*stuff)' => 'not_found#nothing' diff --git a/lib/noosfero/api/api.rb b/lib/noosfero/api/api.rb index 2d0cdd3..5f01a17 100644 --- a/lib/noosfero/api/api.rb +++ b/lib/noosfero/api/api.rb @@ -52,6 +52,8 @@ module Noosfero mount Session + add_swagger_documentation api_version: 'v1', mount_path: '/api_docs', markdown: GrapeSwagger::Markdown::KramdownAdapter unless Rails.env.production? + # hook point which allow plugins to add Grape::API extensions to API::API #finds for plugins which has api mount points classes defined (the class should extends Grape::API) @plugins = Noosfero::Plugin.all.map { |p| p.constantize } diff --git a/lib/noosfero/api/entities.rb b/lib/noosfero/api/entities.rb index 5f8636f..4b0cbf6 100644 --- a/lib/noosfero/api/entities.rb +++ b/lib/noosfero/api/entities.rb @@ -43,7 +43,7 @@ module Noosfero class Person < Profile root 'people', 'person' - expose :user, :using => UserBasic + expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' } end class Enterprise < Profile @@ -74,11 +74,11 @@ module Noosfero root 'articles', 'article' expose :id expose :body - expose :abstract + expose :abstract, documentation: {type: 'String', desc: 'Teaser of the body'} expose :created_at, :format_with => :timestamp expose :title, :documentation => {:type => "String", :desc => "Title of the article"} - expose :created_by, :as => :author, :using => Profile - expose :profile, :using => Profile + expose :created_by, :as => :author, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile author that create the article'} + expose :profile, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile associated with the article'} expose :categories, :using => Category expose :image, :using => Image #TODO Apply vote stuff in core and make this test @@ -88,7 +88,7 @@ module Noosfero expose :position expose :hits expose :start_date - expose :end_date + expose :end_date, :documentation => {type: 'DateTime', desc: 'The date of finish of the article'} expose :tag_list end @@ -98,6 +98,7 @@ module Noosfero expose :children, using: ArticleBase do |article, options| article.children.limit(Noosfero::API::V1::Articles::MAX_PER_PAGE) end + expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"} end class Comment < Entity @@ -127,7 +128,7 @@ module Noosfero end class UserLogin < User - expose :private_token + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'} end class Task < Entity diff --git a/lib/noosfero/api/v1/articles.rb b/lib/noosfero/api/v1/articles.rb index 5ef335f..30f1519 100644 --- a/lib/noosfero/api/v1/articles.rb +++ b/lib/noosfero/api/v1/articles.rb @@ -21,15 +21,40 @@ module Noosfero # Example Request: # GET host/api/v1/articles?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317 + desc 'Return all articles of all kinds' do + detail 'Get all articles filtered by fields in query params' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticlesList' + headers [ + 'Per-Page' => { + description: 'Total number of records', + required: false + } + ] + end get do present_articles(environment) end - desc "Return the article id" + desc "Return one article by id" do + detail 'Get only one article by id. If not found the "forbidden" http error is showed' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticleById' + end get ':id', requirements: {id: /[0-9]+/} do present_article(environment) end - + + desc 'Report a abuse and/or violent content in a article by id' do + detail 'Submit a abuse (in general, a content violation) report about a specific article' + params Noosfero::API::Entities::Article.documentation + failure [[400, 'Bad Request']] + named 'ArticleReportAbuse' + end post ':id/report_abuse' do article = find_article(environment.articles, params[:id]) profile = article.profile @@ -58,14 +83,23 @@ module Noosfero end - desc "Returns the total followers for the article" + desc "Returns the total followers for the article" do + detail 'Get the followers of a specific article by id' + failure [[403, 'Forbidden']] + named 'ArticleFollowers' + end get ':id/followers' do article = find_article(environment.articles, params[:id]) total = article.person_followers.count {:total_followers => total} end - desc "Add a follower for the article" + desc "Add a follower for the article" do + detail 'Add the current user identified by private token, like a follower of a article' + params Noosfero::API::Entities::UserLogin.documentation + failure [[401, 'Unauthorized']] + named 'ArticleFollow' + end post ':id/follow' do authenticate! article = find_article(environment.articles, params[:id]) @@ -80,6 +114,12 @@ module Noosfero end end + desc 'Perform a vote on a article by id' do + detail 'Vote on a specific article with values: 1 (if you like) or -1 (if not)' + params Noosfero::API::Entities::UserLogin.documentation + failure [[401,'Unauthorized']] + named 'ArticleVote' + end post ':id/vote' do authenticate! value = (params[:value] || 1).to_i @@ -90,6 +130,12 @@ module Noosfero {:vote => vote.save} end + desc 'Return the children of a article identified by id' do + detail 'Get all children articles of a specific article' + params Noosfero::API::Entities::Article.documentation + failure [[403, 'Forbidden']] + named 'ArticleChildren' + end get ':id/children' do article = find_article(environment.articles, params[:id]) @@ -108,6 +154,13 @@ module Noosfero present articles, :with => Entities::Article, :fields => params[:fields] end + desc 'Return one child of a article identified by id' do + detail 'Get a child of a specific article' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticleChild' + end get ':id/children/:child_id' do article = find_article(environment.articles, params[:id]) child = find_article(article.children, params[:child_id]) @@ -115,6 +168,13 @@ module Noosfero present child, :with => Entities::Article, :fields => params[:fields] end + desc 'Suggest a article to another profile' do + detail 'Suggest a article to another profile (person, community...)' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Task + failure [[401,'Unauthorized']] + named 'ArticleSuggest' + end post ':id/children/suggest' do authenticate! parent_article = environment.articles.find(params[:id]) @@ -133,6 +193,13 @@ module Noosfero # Example Request: # POST api/v1/articles/:id/children?private_token=234298743290432&article[name]=title&article[body]=body + desc 'Add a child article to a parent identified by id' do + detail 'Create a new article and associate to a parent' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[401,'Unauthorized']] + named 'ArticleAddChild' + end post ':id/children' do authenticate! parent_article = environment.articles.find(params[:id]) @@ -162,6 +229,14 @@ module Noosfero resource kind.pluralize.to_sym do segment "/:#{kind}_id" do resource :articles do + + desc "Return all articles associate with a profile of type #{kind}" do + detail 'Get a list of articles of a profile' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticlesOfProfile' + end get do profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) @@ -178,6 +253,13 @@ module Noosfero end end + desc "Return a article associate with a profile of type #{kind}" do + detail 'Get only one article of a profile' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticleOfProfile' + end get ':id' do profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) present_article(profile) @@ -185,6 +267,13 @@ module Noosfero # Example Request: # POST api/v1/{people,communities,enterprises}/:asset_id/articles?private_token=234298743290432&article[name]=title&article[body]=body + desc "Add a new article associated with a profile of type #{kind}" do + detail 'Create a new article and associate with a profile' + params Noosfero::API::Entities::Article.documentation + success Noosfero::API::Entities::Article + failure [[403, 'Forbidden']] + named 'ArticleCreateToProfile' + end post do profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) post_article(profile, params) -- libgit2 0.21.2