apipony 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ <li class="attribute-container">
2
+ <div class="attribute">
3
+ <div class="attribute-name name">
4
+ <%= attribute.name %>
5
+ </div>
6
+
7
+ <div class="attribute-type type">
8
+ <% if attribute.is_subtype? %>
9
+ <%= link_to root_path(:anchor => "subtype-#{attribute.type}") do %>
10
+ <%= attribute.type %>
11
+ <% end %>
12
+ <% else %>
13
+ <%= attribute.type %>
14
+ <% end %>
15
+ </div>
16
+
17
+ <% if attribute.description %>
18
+ <div class="attribute-description"><%= attribute.description %></div>
19
+ <% end %>
20
+ </div>
21
+
22
+ <% if attribute.is_enum? %>
23
+ <ul class="attribute-enum-list">
24
+ <div class="title">Possible values</div>
25
+ <% attribute.choices.each do |choice| %>
26
+ <li class="attribute-enum-member">
27
+ <div class="attribute-enum-member-name"><%= choice.name %></div>
28
+ <div class="attribute-enum-member-description"><%= choice.description %></div>
29
+ </li>
30
+ <% end %>
31
+ </ul>
32
+ <% end %>
33
+
34
+ <% if attribute.is_object? %>
35
+ <ul class="attribute-object-list">
36
+ <div class="title">Child attributes</div>
37
+ <%= render partial: "attribute",
38
+ collection: attribute.attributes,
39
+ as: :attribute %>
40
+ </ul>
41
+ <% end %>
42
+ </li>
@@ -0,0 +1,8 @@
1
+ <footer>
2
+ <div class="container">
3
+ Powered by
4
+ <%= link_to 'https://github.com/droptheplot/apipony' do %>
5
+ <i class="fa fa-github"></i> Apipony
6
+ <% end %>
7
+ </div>
8
+ </footer>
@@ -0,0 +1,8 @@
1
+ <header>
2
+ <div class="container">
3
+ <%= link_to @documentation.title, root_path, class: 'title' %>
4
+ <% if main_app.root_path %>
5
+ <%= link_to 'Back to site', main_app.root_path, class: 'back' %>
6
+ <% end %>
7
+ </div>
8
+ </header>
@@ -0,0 +1 @@
1
+ <span class="method <%= endpoint.method %>"><%= endpoint.method %></span><%= endpoint.url %>
@@ -0,0 +1,37 @@
1
+ <div class="request">
2
+ <h4>Request&#58;</h4>
3
+ <% if endpoint.request.params %>
4
+ <div class="panel">
5
+ <div class="title">Parameters</div>
6
+ <table class="table">
7
+ <% endpoint.request.params.each do |param| %>
8
+ <tr class="parameters">
9
+ <td class="name">
10
+ <%= param.name %>
11
+ </td>
12
+ <td class="type">
13
+ <%= param.type %>
14
+ </td>
15
+ <td class="required">
16
+ <% if param.required %>
17
+ <i class="fa fa-check-square-o" title="Required"></i>
18
+ <% else %>
19
+ <i class="fa fa-square-o" title="Optional"></i>
20
+ <% end %>
21
+ </td>
22
+ <td class="example">
23
+ <%= param.example %>
24
+ </td>
25
+ </tr>
26
+ <% end %>
27
+ </table>
28
+ </div>
29
+ <% end %>
30
+
31
+ <% if endpoint.request.headers %>
32
+ <div class="panel">
33
+ <div class="title">Headers</div>
34
+ <pre class="code"><%= JSON.pretty_generate(endpoint.request.headers) %></pre>
35
+ </div>
36
+ <% end %>
37
+ </div>
@@ -0,0 +1,30 @@
1
+ <div class="response">
2
+ <h4>Response: <%= response.status %></h4>
3
+ <% if response.example %>
4
+ <div class="response-example">
5
+ <%# This is kind of fancy for no reason but whatever %>
6
+ <% if response.example.headers %>
7
+ <div class="title">Headers</div>
8
+ <pre class="code hljs json"><%= JSON.pretty_generate(response.example.headers) %></pre>
9
+ <% end %>
10
+
11
+ <% if response.example.body %>
12
+ <div class="panel">
13
+ <div class="title">Body</div>
14
+ <pre class="code hljs json"><%= JSON.pretty_generate(response.example.body) %></pre>
15
+ </div>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+
20
+ <% if response.attributes.size > 0 %>
21
+ <div class="panel">
22
+ <div class="title">Attributes</div>
23
+ <div class="table">
24
+ <div class="attributes">
25
+ <%= render partial: 'attribute', collection: response.attributes, as: :attribute %>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <% end %>
30
+ </div>
@@ -0,0 +1,16 @@
1
+ <% @documentation.sections.each do |section| %>
2
+ <h4>
3
+ <%= link_to section.title, root_path(:anchor => section.title) %>
4
+ </h4>
5
+ <ul>
6
+ <% section.endpoints.each do |endpoint| %>
7
+ <li>
8
+ <h5>
9
+ <%= link_to root_path(:anchor => endpoint.id) do %>
10
+ <span class="method <%= endpoint.method %>"><%= endpoint.method %></span><%= endpoint.url %>
11
+ <% end %>
12
+ </h5>
13
+ </li>
14
+ <% end %>
15
+ </ul>
16
+ <% end %>
@@ -0,0 +1,60 @@
1
+ <%= render partial: "header" %>
2
+
3
+ <main>
4
+ <div class="container">
5
+ <div class="row">
6
+ <div class="sidebar">
7
+ <%= render partial: "sidebar" %>
8
+ </div>
9
+
10
+ <div class="main-col">
11
+ <% @documentation.sections.each do |section| %>
12
+ <div class="section">
13
+ <h2 id="<%= section.title %>"><%= section.title %></h2>
14
+ <% section.endpoints.each do |endpoint| %>
15
+ <div class="endpoint" id="<%= endpoint.id %>">
16
+ <h3><%= render "method", endpoint: endpoint %></h3>
17
+
18
+ <% if endpoint.description %>
19
+ <div class="description">
20
+ <%= endpoint.description %>
21
+ </div>
22
+ <% end %>
23
+
24
+ <% if endpoint.request || endpoint.response %>
25
+ <% if endpoint.request %>
26
+ <%= render "request", endpoint: endpoint %>
27
+ <% end %>
28
+
29
+ <% if endpoint.response %>
30
+ <%= render "response", response: endpoint.response %>
31
+ <% end %>
32
+ <% end %>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ <% end %>
37
+
38
+ <div id="defined_subtypes">
39
+ <% @documentation.subtypes.each do |name, type| %>
40
+ <div class="subtype" id="subtype-<%= name %>">
41
+ <h4><%= name %></h4>
42
+ <div class="panel">
43
+ <div class="title">Attributes</div>
44
+ <div class="table">
45
+ <div class="attributes">
46
+ <%= render partial: "attribute",
47
+ collection: type.attributes,
48
+ as: :attribute %>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ <% end %>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </main>
59
+
60
+ <%= render partial: "footer" %>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <head>
3
+ <%# UTF-8 Character Set %>
4
+ <meta charset="utf-8">
5
+
6
+ <%# HTML Title %>
7
+ <title><%= @documentation.title %></title>
8
+
9
+ <%# Viewport meta tag %>
10
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
11
+
12
+ <link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/github.min.css'>
13
+ <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css'>
14
+ <%= stylesheet_link_tag 'apipony/application', media: 'all' %>
15
+ <script src='//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js'></script>
16
+ <%= javascript_include_tag 'apipony/application' %>
17
+ <%= csrf_meta_tags %>
18
+ </head>
19
+ <body>
20
+ <%= yield %>
21
+ </body>
22
+ </html>
data/lib/apipony.rb CHANGED
@@ -7,6 +7,25 @@ require 'apipony/endpoint'
7
7
  require 'apipony/response'
8
8
  require 'apipony/request'
9
9
  require 'apipony/parameter'
10
+ require 'apipony/response_attribute'
11
+ require 'apipony/example_response'
10
12
 
11
13
  module Apipony
14
+
15
+ ##
16
+ # This allows you to define a common sub-type of attributes.
17
+ # A typical example is something like a list of users. If you want to
18
+ # display all users who created an image, who subscribe to a channel, or who
19
+ # are in a group, it may be useful if the information on those users is in a
20
+ # common format. This lets you define one common format, which you can then
21
+ # merge in to other attributes.
22
+ # = Example
23
+ # Apipony.define_attribute_type :user_stub do
24
+ # attribute :name
25
+ # attribute :id
26
+ # end
27
+ def self.define_attribute_type(name, **params, &block)
28
+ a = Apipony::ResponseAttribute.new("", **params, &block)
29
+ Apipony::ResponseAttribute.define_type(name, a)
30
+ end
12
31
  end
@@ -1,3 +1,5 @@
1
+ ##
2
+ # Top-level class for the DSL
1
3
  class Apipony::Documentation
2
4
  class << self
3
5
  attr_accessor :title, :base_url, :sections
@@ -9,11 +11,33 @@ class Apipony::Documentation
9
11
 
10
12
  instance_eval(&block)
11
13
  end
14
+ ##
15
+ # @return [Hash<String, ApiPony::ResponseAttribute] a hash of each subype.
16
+ # keys are the names of the subtype, values are the attribute object that
17
+ # defines it
18
+ def subtypes
19
+ Apipony::ResponseAttribute.defined_subtypes
20
+ end
12
21
 
22
+ ##
23
+ # Start a new section.
24
+ # Sections are logically separated on the display page.
13
25
  def section(title, &block)
14
26
  @sections << Apipony::Section.new(title, &block)
15
27
  end
16
28
 
29
+ ##
30
+ # Define a new subtype.
31
+ # A subtype describes a common object used in various places in your Api.
32
+ # Once defined, setting the `type` of an attribute to this given name will
33
+ # cause it to reference this subtype in a common location.
34
+ # @param [String] name what to call this subtype
35
+ def subtype(name, **params, &block)
36
+ Apipony.define_attribute_type(name, **params, &block)
37
+ end
38
+
39
+ ##
40
+ # Configure API pony with the DSL
17
41
  def config(&block)
18
42
  instance_eval(&block)
19
43
  end
@@ -1,5 +1,20 @@
1
+ ##
2
+ # Model a response endpoint.
1
3
  class Apipony::Endpoint < Apipony::Base
2
- attr_accessor :method, :url, :description, :response, :request
4
+ ##
5
+ # What HTTP verb to use to access this endpoint
6
+ attr_accessor :method
7
+ ##
8
+ # The URl of this endpoint
9
+ attr_accessor :url
10
+
11
+ ##
12
+ # A short description of what this endpoint does and why it may be useful.
13
+ attr_accessor :description
14
+
15
+ ##
16
+ #:nodoc:
17
+ attr_accessor :response, :request
3
18
 
4
19
  def initialize(method, url, &block)
5
20
  @method = method
@@ -8,14 +23,20 @@ class Apipony::Endpoint < Apipony::Base
8
23
  instance_eval(&block) if block_given?
9
24
  end
10
25
 
11
- def response_with(status, &block)
12
- @response = Apipony::Response.new(status, &block)
26
+ ##
27
+ # DSL method to start describing a response
28
+ def response_with(status, **params, &block)
29
+ @response = Apipony::Response.new(status, **params, &block)
13
30
  end
14
31
 
32
+ ##
33
+ # DSL method to start describind a request
15
34
  def request_with(&block)
16
35
  @request = Apipony::Request.new(&block)
17
36
  end
18
37
 
38
+ ##
39
+ # Create a unique identifier for this endpoint
19
40
  def id
20
41
  File.join(@method, @url)
21
42
  end
@@ -1,4 +1,6 @@
1
1
  module Apipony
2
+ ##
3
+ # Rails engine so you can just drop Apipony right into your application
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace Apipony
4
6
  end
@@ -0,0 +1,9 @@
1
+ ##
2
+ # Display an example response to help with understanding of the API.
3
+ class Apipony::ExampleResponse < Apipony::Base
4
+ attr_accessor :headers, :body
5
+ def initialize(&block)
6
+ instance_eval(&block) if block_given?
7
+ end
8
+
9
+ end
@@ -1,10 +1,11 @@
1
1
  class Apipony::Parameter < Apipony::Base
2
- attr_accessor :name, :type, :example, :required
2
+ attr_accessor :name, :type, :example, :required, :description
3
3
 
4
- def initialize(name, example, type, required)
4
+ def initialize(name, example, type, required, description)
5
5
  @name = name
6
6
  @example = example
7
7
  @type = type
8
8
  @required = required
9
+ @description = description
9
10
  end
10
11
  end
@@ -1,13 +1,26 @@
1
+ ##
2
+ # Model a request that an API user can make.
3
+ # Includes information about required parameters and required headers
1
4
  class Apipony::Request < Apipony::Base
2
- attr_accessor :params, :headers
5
+ ##
6
+ # :nodoc:
7
+ attr_accessor :params
8
+ ##
9
+ #:nodoc:
10
+ attr_accessor :headers
3
11
 
4
12
  def initialize(&block)
5
13
  @params = []
6
14
 
7
15
  instance_eval(&block)
8
16
  end
9
-
10
- def param(name, example: '', type: :string, required: false)
11
- @params << Apipony::Parameter.new(name, example, type, required)
17
+ ##
18
+ # Construct a new parameter
19
+ def param(name,
20
+ example: '',
21
+ type: :string,
22
+ required: false,
23
+ description: '')
24
+ @params << Apipony::Parameter.new(name, example, type, required, description)
12
25
  end
13
26
  end
@@ -1,9 +1,51 @@
1
- class Apipony::Response < Apipony::Base
2
- attr_accessor :status, :headers, :body
3
-
4
- def initialize(status, &block)
1
+ class Apipony::Response
2
+ attr_accessor :example, :attributes, :status
3
+ def initialize(status, array: false, &block)
5
4
  @status = status
6
-
5
+ @attributes = []
6
+ @array = array
7
7
  instance_eval(&block) if block_given?
8
8
  end
9
+
10
+ def is_array?
11
+ !! @array
12
+ end
13
+
14
+ def example(&block)
15
+ if block_given?
16
+ @example = Apipony::ExampleResponse.new(&block)
17
+ else
18
+ find_example
19
+ end
20
+ end
21
+
22
+ def attribute(name, **params, &block)
23
+ if params[:example]
24
+ @use_attribute_examples = true
25
+ end
26
+ @attributes << Apipony::ResponseAttribute.new(name, **params, &block)
27
+ end
28
+ private
29
+ def find_example
30
+ if @use_attribute_examples
31
+ build_example_from_attributes
32
+ end
33
+ @example
34
+ end
35
+
36
+ def build_example_from_attributes
37
+ build = Hash.new
38
+ @attributes.each do |attr|
39
+ build[attr.name] = attr.example if attr.example
40
+ end
41
+ @example ||= Apipony::ExampleResponse.new
42
+ case @example.body
43
+ when Hash
44
+ @example.body.merge! build
45
+ @example.body = [@example.body] if is_array?
46
+ when NilClass
47
+ @example.body = (is_array? ? [build] : build)
48
+ end
49
+ @example
50
+ end
9
51
  end