apipony 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86b81077625eb78efec26c41c96c30e832ef5c02
4
- data.tar.gz: d05befea092568084df3b920dfbc5ed4ea64f17d
3
+ metadata.gz: 4c3166ea73b31da19b4bda3071ae02dcfa4d4ca9
4
+ data.tar.gz: 5a6d604772716180f128ef341ff9df54e0a03eac
5
5
  SHA512:
6
- metadata.gz: 5fe9cdb7e1cfea04e9d4bac98aee904753b87750048da48fc4c37c826b9232bf709c17d1ed58f9c5c146b50f22915abc3cb91e054d85bd2c0c220d4c354c522c
7
- data.tar.gz: 2b756e4a6ec30fe410c96d8fa6d609dac9d73284b8c7f7b3bb594427d178873c97c857ce60a6d022d5ed629d6bea18aba6527a03f37d7b379b1a5961e6fbc698
6
+ metadata.gz: e734f9f86495b7ee3d9f10b16bd3148f43264133ca7a388f3c4e6067ce2af65c9bbe1ebd480697bc88c97bba20fc760c1f883ee3770948b8f055a6fad120f3b8
7
+ data.tar.gz: 52c6232bf579dc49170f7c8699e8f183449af9e66a63488e721f6502cc16d9652341f29f01036ef98d1530f51c9f55047848df1c95ab570522e6c3afc32a79dc
data/README.md CHANGED
@@ -1,19 +1,20 @@
1
1
  # Apipony
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/apipony.svg)](https://badge.fury.io/rb/apipony)
4
+ [![Build Status](https://travis-ci.org/droptheplot/apipony.svg?branch=travis)](https://travis-ci.org/droptheplot/apipony)
4
5
  [![Code Climate](https://codeclimate.com/github/droptheplot/apipony/badges/gpa.svg)](https://codeclimate.com/github/droptheplot/apipony)
5
6
 
6
7
  Ruby DSL to create Rails API documentation from your application.
7
8
 
8
- ## Getting started
9
9
 
10
+ ## Getting started
10
11
  * Add `gem 'apipony'` to Gemfile
11
12
  * `bundle install`
12
13
  * `rails g apipony:install`
13
14
  * Now you can edit your documentation in `config/initializers/apipony.rb`
14
15
 
15
- ## How it works
16
16
 
17
+ ## How it works
17
18
  DSL example:
18
19
 
19
20
  ```ruby
@@ -28,7 +29,7 @@ Apipony::Documentation.define do
28
29
  e.description = 'Find ponies'
29
30
 
30
31
  request_with do
31
- param :name, example: 'applejack', required: true
32
+ param :name, example: 'applejack', required: true
32
33
  end
33
34
 
34
35
  response_with 200 do
@@ -44,6 +45,207 @@ Apipony::Documentation.define do
44
45
  end
45
46
  ```
46
47
 
48
+
49
+ ## Features
50
+
51
+ ### Response Attribute Documentation
52
+ Apipony lets you provide further documentation about the attributes in your
53
+ API's responses. Simply create a new `attribute` inside a `respond_with` block.
54
+ These attributes can even have nested sub-attributes, for documentation of
55
+ more complex object graphs.
56
+
57
+ ```ruby
58
+ Apipony::Documentation.define do
59
+ section "Species" do
60
+ endpoint 'get', '/species/:id' do |e|
61
+ e.description = "Get information about a species"
62
+ respond_with 200 do
63
+ example do
64
+ set :body, {
65
+ name: "Unicorn",
66
+ is_pony: true,
67
+ biology: {
68
+ has_horn: true,
69
+ has_wings: false
70
+ }
71
+ }
72
+ end
73
+ attribute :name, type: :string
74
+ attribute :is_pony, type: :bool,
75
+ description: "Is this species a type of pony?"
76
+ attribute :biology do
77
+ attribute :has_horn, type: :bool
78
+ attribute :has_wings, type: :bool
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ ```
85
+
86
+ ### Enum Attributes
87
+ Your API may have some fields that can be picked from a pre-defined set of
88
+ values. You can document those values by using an enum attribute.
89
+
90
+ ```ruby
91
+ Apipony::Documentation.define do
92
+ section "Ponies" do
93
+ endpoint "get", "/ponies/:id" do |e|
94
+ e.description = "Information about a pony"
95
+ example do
96
+ set :body, {
97
+ name: "Applejack",
98
+ sex: "female",
99
+ kind: :earth,
100
+ occupation: :farmer
101
+ }
102
+ end
103
+
104
+ attribute :kind, type: :enum do
105
+ choice :earth, description: "A pony with no wings or horn"
106
+ choice :unicorn, description: "A pony with a horn"
107
+ choice :pegasus, description: "A pony with wings"
108
+ choice :alicorn,
109
+ description: "A pony with wings and a horn. Indicates royalty."
110
+ end
111
+ end
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Example Generation
117
+ When describing attributes, you can provide an optional `example:` parameter.
118
+ If included, this will be used to generate the example response in the
119
+ documentation.
120
+
121
+ ```ruby
122
+ Apipony::Documentation.define do
123
+ section "Ponies" do
124
+ endpoint "get", "/ponies/:id" do |e|
125
+ respond_with 200 do
126
+ attribute :name, type: :string, example: "Applejack"
127
+ # Enum members automatically select the first choice
128
+ attribute :kind, type: :enum do
129
+ choice :earth
130
+ choice :pegasus
131
+ choice :unicorn
132
+ choice :alicorn
133
+ end
134
+ end
135
+ end
136
+
137
+ endpoint "get", "/ponies/" do |e|
138
+ # Automatic serialization of arrays is supported
139
+ respond_with 200, array: true do
140
+ attribute :name, type: :string, example: "Applejack"
141
+ attribute :id, type: :integer, example: 10
142
+ end
143
+ end
144
+ end
145
+ end
146
+ ```
147
+
148
+ `GET /ponies/:id` will now have the example of:
149
+
150
+ ```json
151
+ {
152
+ "name": "Applejack",
153
+ "kind": "Earth"
154
+ }
155
+ ```
156
+
157
+ `GET /ponies/` will have the example of:
158
+
159
+ ```json
160
+ [
161
+ {
162
+ "name": "Applejack",
163
+ "id": 10
164
+ }
165
+ ]
166
+ ```
167
+
168
+ ### Predefined Subtypes
169
+ Sometimes, when building an API, it can be useful to store data in a common
170
+ format. Apipony lets you define this common format once, then use it multiple
171
+ times. Check it out:
172
+
173
+ ```ruby
174
+ Apipony::Documentation.define do
175
+ subtype :pony_stub do
176
+ attribute :name, type: :string
177
+ attribute :id, type: :integer
178
+ end
179
+
180
+ section "Ponies" do
181
+ endpoint 'get', '/ponies/:id' do |e|
182
+ e.description = "Find a pony with a given name"
183
+ request_with do
184
+ params :id, example: 10, required: true
185
+ end
186
+
187
+ response_with 200 do
188
+ example do
189
+ set :body, {
190
+ :name => :applejack,
191
+ :type => :earth,
192
+ :sex => :female,
193
+ :occupation => :farmer,
194
+ :friends => [
195
+ {name: "Twilight Sparkle", id: 1},
196
+ {name: "Pinkie Pie", id: 2},
197
+ {name: "Rainbow Dash", id: 3},
198
+ {name: "Rarity", id: 4},
199
+ {name: "Fluttershy", id: 5}
200
+ ]
201
+ }
202
+ end
203
+ attribute :name, type: :string
204
+ attribute :kind, type: :enum do
205
+ choice :alicorn
206
+ choice :earth
207
+ choice :unicorn
208
+ choice :pegasus
209
+ end
210
+ attribute :friends, type: :pony_stub, array: true
211
+ attribute :occupation, type: :string
212
+ end
213
+ end
214
+
215
+ section "Locations" do
216
+ endpoint 'get', '/locations/:id' do |e|
217
+ e.description = "Information about a location"
218
+ response_with 200 do
219
+ example do
220
+ set :body, {
221
+ :name => "Crystal Empire",
222
+ :population => 107770,
223
+ :rulers => [
224
+ {
225
+ name: "Shining Armor",
226
+ id: 50
227
+ },
228
+ {
229
+ name: "Princess Cadence",
230
+ id: 90001
231
+ }
232
+ ]
233
+ }
234
+ end
235
+ attribute :name, type: :string
236
+ attribute :population, type: :integer
237
+ attribute :rulers, type: :pony_stub, array: true
238
+ end
239
+ end
240
+ end
241
+ end
242
+ ```
243
+
244
+ Now, the `friends` attribute of `GET /ponies/:id` and the `rulers` attribute of
245
+ `GET /locations/:id` will reference a common subtype on the generated
246
+ documentation.
247
+
248
+
47
249
  Generated documentation example:
48
250
 
49
251
  ![Example](https://raw.githubusercontent.com/droptheplot/apipony/master/preview.png)
data/Rakefile CHANGED
@@ -1,20 +1,16 @@
1
1
  begin
2
2
  require 'bundler/setup'
3
+ require 'yard'
3
4
  rescue LoadError
4
5
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
6
  end
6
7
 
7
8
  require 'rdoc/task'
8
9
 
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Apipony'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
10
+ YARD::Rake::YardocTask.new(:doc) do |doc|
15
11
  end
16
12
 
17
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
13
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
14
  load 'rails/tasks/engine.rake'
19
15
 
20
16
 
@@ -1,13 +1,25 @@
1
+ // Color scheme
1
2
  $dark_color: #111;
2
3
  $medium_color: #888;
3
4
  $light_color: #eee;
4
- $brand_color: #5E147D;
5
+ $brand_color: #5e147d;
5
6
 
6
- @import url(https://fonts.googleapis.com/css?family=Cuprum&subset=latin,cyrillic);
7
+ // Method colors
8
+ $get-color: #1abc9c;
9
+ $post-color: #3498db;
10
+ $put-color: #2980d9;
11
+ $delete-color: #c0392b;
7
12
 
8
- * {
13
+ // Misc. values
14
+ $transition-time: 200ms;
15
+ $mobile-width: 900px;
16
+
17
+
18
+ *, *::before, *::after {
9
19
  margin: 0;
10
20
  padding: 0;
21
+ box-sizing: border-box;
22
+
11
23
  &:focus {
12
24
  outline: none;
13
25
  }
@@ -19,8 +31,8 @@ html, body {
19
31
  }
20
32
 
21
33
  body {
22
- font-family: 'Arial';
23
- font-size: 14px;
34
+ font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
35
+ font-size: 12px;
24
36
  color: $dark_color;
25
37
  -webkit-font-smoothing: antialiased;
26
38
  }
@@ -45,8 +57,9 @@ h2 {
45
57
  }
46
58
 
47
59
  h3 {
60
+ padding-top: 10px;
48
61
  font-size: 17px;
49
- line-height: 17px;
62
+ line-height: 16px;
50
63
  }
51
64
 
52
65
  h4 {
@@ -57,17 +70,22 @@ h4 {
57
70
 
58
71
  h5 {
59
72
  font-weight: normal;
73
+ font-size: 12px;
74
+ line-height: 17px;
60
75
  }
61
76
 
62
77
  ul {
63
78
  margin-bottom: 20px;
79
+
64
80
  li {
65
81
  margin-bottom: 10px;
66
82
  }
67
83
  }
68
84
 
69
85
  .container {
70
- width: 940px;
86
+ max-width: 900px;
87
+ width: 100%;
88
+ padding: 0 20px;
71
89
  margin: 0 auto;
72
90
  position: relative;
73
91
  }
@@ -75,20 +93,28 @@ ul {
75
93
  .row {
76
94
  overflow: hidden;
77
95
  margin: 0 -10px;
96
+ display: flex;
97
+ flex-flow: row nowrap;
98
+
99
+ @media all and (max-width: $mobile-width) {
100
+ flex-flow: row wrap;
101
+ }
78
102
  }
79
103
 
80
- @for $i from 1 through 12 {
81
- .col-#{$i} {
82
- box-sizing: border-box;
83
- margin: 0 10px;
84
- width: 60px * $i + 20px * ($i - 1);
85
- float: left;
104
+ .sidebar {
105
+ flex: 1 120px;
106
+
107
+ @media all and (max-width: $mobile-width) {
108
+ flex: 1 100%;
109
+ margin-bottom: 30px;
86
110
  }
87
111
  }
88
112
 
89
- @for $i from 1 through 12 {
90
- .col-offset-#{$i} {
91
- margin-left: 60px * $i + 20px * ($i - 1) + 30px;
113
+ .main-col {
114
+ flex: 8;
115
+
116
+ @media all and (max-width: $mobile-width) {
117
+ flex: 1 100%;
92
118
  }
93
119
  }
94
120
 
@@ -96,17 +122,23 @@ header {
96
122
  background: $brand_color;
97
123
  height: 60px;
98
124
  line-height: 60px;
125
+
99
126
  .title {
100
- font-family: 'Cuprum';
101
127
  font-weight: bold;
102
128
  font-size: 20px;
103
129
  color: #fff;
104
130
  }
131
+
105
132
  .back {
106
133
  float: right;
107
134
  color: #fff;
108
- opacity: .7;
135
+ opacity: 0.7;
109
136
  font-size: 12px;
137
+ transition: $transition-time opacity;
138
+
139
+ &:hover {
140
+ opacity: 1;
141
+ }
110
142
  }
111
143
  }
112
144
 
@@ -120,8 +152,15 @@ footer {
120
152
  border-top: 1px solid $light_color;
121
153
  text-align: right;
122
154
  font-size: 12px;
155
+ color: $medium_color;
156
+
123
157
  a {
124
158
  color: $medium_color;
159
+ transition: $transition-time color;
160
+
161
+ &:hover {
162
+ color: $dark-color;
163
+ }
125
164
  }
126
165
  }
127
166
 
@@ -131,22 +170,27 @@ footer {
131
170
  margin-bottom: 40px;
132
171
  border-bottom: 1px solid $light_color;
133
172
  }
173
+
134
174
  .endpoint {
135
175
  position: relative;
176
+
136
177
  &:not(:last-child) {
137
178
  margin-bottom: 40px;
138
179
  }
180
+
139
181
  .description {
140
182
  font-size: 12px;
141
183
  color: $medium_color;
142
184
  padding-top: 20px;
143
185
  font-weight: normal;
144
186
  }
187
+
145
188
  .response, .request {
146
189
  padding-top: 20px;
190
+
147
191
  .code {
148
192
  padding: 8px 10px 10px;
149
- font-size: 12px;
193
+ font-size: 14px;
150
194
  border-radius: 0 0 3px 3px;
151
195
  }
152
196
  }
@@ -157,48 +201,60 @@ footer {
157
201
  border: 1px solid darken($light_color, 5%);
158
202
  border-radius: 3px;
159
203
  margin-top: 20px;
204
+ overflow-x: auto;
205
+
160
206
  .title {
161
207
  border-bottom: 1px solid darken($light_color, 5%);
162
208
  padding: 10px;
163
- font-size: 11px;
209
+ font-size: 12px;
164
210
  font-weight: bold;
165
211
  }
166
212
  }
167
213
 
168
214
  .method {
169
215
  text-transform: uppercase;
216
+ vertical-align: bottom;
170
217
  color: #fff;
171
218
  font-size: 9px;
172
219
  padding: 4px 5px;
173
220
  border-radius: 3px;
174
221
  margin-right: 5px;
175
222
  font-weight: bold;
176
- background: $medium_color;
223
+ background-color: $medium_color;
224
+
177
225
  &.get {
178
- background: #1ABC9C;
226
+ background-color: $get-color;
179
227
  }
228
+
180
229
  &.post {
181
- background: #3498DB;
230
+ background-color: $post-color;
182
231
  }
232
+
183
233
  &.put {
184
- background: #2980B9;
234
+ background-color: $put-color;
185
235
  }
236
+
186
237
  &.delete {
187
- background: #C0392B;
238
+ background-color: $delete-color;
188
239
  }
189
240
  }
190
241
 
191
- .param {
242
+ .parameters, .attributes {
243
+ font-size: 12px;
244
+
192
245
  .name {
193
246
  color: $brand_color;
194
247
  font-weight: bold;
195
248
  }
249
+
196
250
  .type {
197
251
  color: $medium_color;
198
252
  font-style: italic;
199
253
  }
254
+
200
255
  .required {
201
256
  text-align: center;
257
+
202
258
  .fa {
203
259
  color: $medium_color;
204
260
  }
@@ -207,9 +263,79 @@ footer {
207
263
 
208
264
  .table {
209
265
  padding: 8px 0;
266
+
210
267
  tr {
211
268
  td {
212
- padding: 2px 10px;
269
+ padding: 4px 10px;
270
+ }
271
+ }
272
+ }
273
+
274
+ .attribute-container {
275
+ display: flex;
276
+ flex-flow: column nowrap;
277
+
278
+ .attribute {
279
+ display: flex;
280
+ flex-flow: row nowrap;
281
+ align-items: inherit;
282
+ justify-content: flex-start;
283
+
284
+ > div {
285
+ padding: 4px 10px;
286
+ }
287
+
288
+ .attribute-type {
289
+ flex: 1 1 60px;
290
+ }
291
+
292
+ .attribute-name {
293
+ flex: 2 1 0;
294
+ min-width: 90px;
295
+ }
296
+
297
+ .attribute-description {
298
+ flex: 8 1 0;
299
+ }
300
+ }
301
+
302
+ ul {
303
+ margin: 8px 10px;
304
+ border: 1px solid #e1e1e1;
305
+ border-radius: 3px;
306
+
307
+ li {
308
+ list-style: none;
309
+ margin: 10px 0;
310
+ padding: 0 12px;
213
311
  }
214
312
  }
215
313
  }
314
+
315
+ .attribute-enum-member {
316
+ display: flex;
317
+ flex-flow: row nowrap;
318
+
319
+ .title {
320
+ border-bottom: 1px solid darken($light_color, 5%);
321
+ padding: 10px;
322
+ font-size: 11px;
323
+ font-weight: bold;
324
+ }
325
+
326
+ .attribute-enum-member-name {
327
+ font-weight: 400;
328
+ margin-right: 10px;
329
+ min-width: 60px;
330
+ flex: 1 1 0;
331
+ color: $brand_color;
332
+ }
333
+
334
+ .attribute-enum-member-description {
335
+ flex: 7 1 0;
336
+ }
337
+ }
338
+
339
+ .subtype {
340
+ margin-bottom: 25px;
341
+ }