apipony 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +205 -3
- data/Rakefile +3 -7
- data/app/assets/stylesheets/apipony/styles.scss +153 -27
- data/app/views/apipony/application/_attribute.html.erb +42 -0
- data/app/views/apipony/application/_footer.html.erb +8 -0
- data/app/views/apipony/application/_header.html.erb +8 -0
- data/app/views/apipony/application/_method.html.erb +1 -0
- data/app/views/apipony/application/_request.html.erb +37 -0
- data/app/views/apipony/application/_response.html.erb +30 -0
- data/app/views/apipony/application/_sidebar.html.erb +16 -0
- data/app/views/apipony/application/index.html.erb +60 -0
- data/app/views/layouts/apipony/application.html.erb +22 -0
- data/lib/apipony.rb +19 -0
- data/lib/apipony/documentation.rb +24 -0
- data/lib/apipony/endpoint.rb +24 -3
- data/lib/apipony/engine.rb +2 -0
- data/lib/apipony/example_response.rb +9 -0
- data/lib/apipony/parameter.rb +3 -2
- data/lib/apipony/request.rb +17 -4
- data/lib/apipony/response.rb +47 -5
- data/lib/apipony/response_attribute.rb +130 -0
- data/lib/apipony/section.rb +11 -2
- data/lib/apipony/version.rb +3 -1
- metadata +42 -19
- data/app/views/apipony/application/index.html.haml +0 -74
- data/app/views/layouts/apipony/application.html.haml +0 -12
- data/config/initializers/haml.rb +0 -1
@@ -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 @@
|
|
1
|
+
<span class="method <%= endpoint.method %>"><%= endpoint.method %></span><%= endpoint.url %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<div class="request">
|
2
|
+
<h4>Request:</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
|
data/lib/apipony/endpoint.rb
CHANGED
@@ -1,5 +1,20 @@
|
|
1
|
+
##
|
2
|
+
# Model a response endpoint.
|
1
3
|
class Apipony::Endpoint < Apipony::Base
|
2
|
-
|
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
|
-
|
12
|
-
|
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
|
data/lib/apipony/engine.rb
CHANGED
data/lib/apipony/parameter.rb
CHANGED
@@ -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
|
data/lib/apipony/request.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
11
|
-
|
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
|
data/lib/apipony/response.rb
CHANGED
@@ -1,9 +1,51 @@
|
|
1
|
-
class Apipony::Response
|
2
|
-
attr_accessor :
|
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
|