heroics 0.0.7 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57ff3e602b9779ad560f218f14288d8871402d33
4
- data.tar.gz: 6763bba24c1ccb627963116ee6f43ed341113703
3
+ metadata.gz: 16b5b5b9ec40a80d7ac06af58ebf2be1e0c773fe
4
+ data.tar.gz: a695f11ee1b3eb7841def942d6239c3a589c0fba
5
5
  SHA512:
6
- metadata.gz: 97435f7696ba084ec24a487ea3a652a880100124981e1ebf7f1e91bebf8baff64c6b281dca44e8480d550d3097ac368e36ddd8a466114841b9811b8dd2f4e072
7
- data.tar.gz: 05282988882070b71e6cf9c9c6834bb65fc91c783da88c08e0163b54a21e97dedec950d9b187593cbed23b18c379404d0a6acb091800cb37adbdf586386c1fd9
6
+ metadata.gz: 3a4e120811c3b4cef5d0cd919173c9b89e8e2b39834bbc103681056fa3e4355b371ff9a7cf27c1b22b3114e1c962f9c6fe45cf11a9a4d5317e9d6ce9d64e5e97
7
+ data.tar.gz: 5ad761a53a1baeb2cbbc6d33aa0239c4742eb61406194a0e68b551ea6283372c84f320b631d255bdbd8e7eba524bf86e284eded0d4576d654390f444f73bb983
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
- [![Build Status](https://travis-ci.org/heroku/heroics.png?branch=master)](https://travis-ci.org/heroku/heroics)
1
+ [![Build Status](https://travis-ci.org/interagent/heroics.png?branch=master)](https://travis-ci.org/interagent/heroics)
2
2
  # Heroics
3
3
 
4
- Ruby HTTP client for APIs represented with JSON schema.
4
+ Ruby HTTP client generator for APIs represented with JSON schema.
5
5
 
6
6
  ## Installation
7
7
 
@@ -19,180 +19,78 @@ Or install it yourself as:
19
19
 
20
20
  ## Usage
21
21
 
22
- ### Instantiate a client from a JSON schema with basic credentials
22
+ ### Generating a client
23
23
 
24
- Heroics instantiates an HTTP client from a JSON schema. The client
25
- will make requests to the API using the credentials from the URL. The
26
- default headers will also be included in all requests.
24
+ Heroics generates an HTTP client from a JSON schema that describes your API.
25
+ Look at [prmd](https://github.com/interagent/prmd) for tooling to help write a
26
+ JSON schema. When you have a JSON schema prepared you can generate a client
27
+ for your API:
27
28
 
28
- ```ruby
29
- require 'cgi'
30
- require 'json'
31
- require 'heroics'
32
-
33
- username = CGI.escape('username')
34
- token = 'token'
35
- url = "https://#{username}:#{token}@api.heroku.com"
36
- options = {default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}}
37
- data = JSON.parse(File.read('schema.json'))
38
- schema = Heroics::Schema.new(data)
39
- client = Heroics.client_from_schema(schema, url, options)
40
29
  ```
41
-
42
- ### Instantiate a client from a JSON schema with an OAuth token
43
-
44
- The client will make requests to the API using an OAuth token when one is
45
- provided.
46
-
47
- ```ruby
48
- oauth_token = 'token'
49
- url = "https://api.heroku.com"
50
- options = {default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}}
51
- data = JSON.parse(File.read('schema.json'))
52
- schema = Heroics::Schema.new(data)
53
- client = Heroics.oauth_client_from_schema(oauth_token, schema, url, options)
30
+ bin/heroics-generator MyApp schema.json https://api.myapp.com > client.rb
54
31
  ```
55
32
 
56
- ### Client-side caching
33
+ ### Passing custom headers
57
34
 
58
- Heroics handles ETags and will cache data on the client if you provide
59
- a [Moneta](https://github.com/minad/moneta) cache instance.
35
+ If your client needs to pass custom headers with each request these can be
36
+ specified using `-H`:
60
37
 
61
- ```ruby
62
- username = CGI.escape('username')
63
- token = 'token'
64
- url = "https://#{username}:#{token}@api.heroku.com/schema"
65
- options = {default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'},
66
- cache: Moneta.new(:File, dir: "#{Dir.home}/.heroics/heroku-api")}
67
- data = JSON.parse(File.read('schema.json'))
68
- schema = Heroics::Schema.new(data)
69
- client = Heroics.client_from_schema(schema, url, options)
70
38
  ```
71
-
72
- ### Making requests
73
-
74
- The client exposes resources as top-level methods. Links described in
75
- the JSON schema for those resources are represented as methods on
76
- those top-level resources. For example, you can [list the apps](https://devcenter.heroku.com/articles/platform-api-reference#app-list)
77
- in your Heroku account:
78
-
79
- ```ruby
80
- apps = client.app.list
39
+ bin/heroics-generator \
40
+ -H "Accept: application/vnd.myapp+json; version=3" \
41
+ MyApp \
42
+ schema.json \
43
+ https://api.myapp.com > client.rb
81
44
  ```
82
45
 
83
- The response received from the server will be returned without
84
- modifications. Response content with type `application/json` is
85
- automatically decoded into a Ruby object.
86
-
87
- ### Handling content ranges
46
+ Pass multiple `-H` options if you need more than one custom header.
88
47
 
89
- Content ranges are handled transparently. In such cases the client
90
- will return an `Enumerator` that can be used to access the data. It
91
- only makes requests to the server to fetch additional data when the
92
- current batch has been exhausted.
93
-
94
- ### Command-line interface
95
-
96
- Heroics includes a builtin CLI that, like the client, is generated
97
- from a JSON schema.
98
-
99
- ```ruby
100
- username = 'username'
101
- token = 'token'
102
- url = "https://#{username}:#{token}@api.heroku.com/schema"
103
- options = {
104
- default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'},
105
- cache: Moneta.new(:File, dir: "#{Dir.home}/.heroics/heroku-api")}
106
- data = JSON.parse(File.read('schema.json'))
107
- schema = Heroics::Schema.new(data)
108
- cli = Heroics.cli_from_schema('heroku-api', STDOUT, schema, url, options)
109
- cli.run(*ARGV)
110
- ```
48
+ ### Client-side caching
111
49
 
112
- Running it without arguments displays usage information:
50
+ The generated client sends and caches ETags received from the server. By
51
+ default, this data is cached in memory and is only used during the lifetime of
52
+ a single instance. You can specify a directory for cache data:
113
53
 
114
54
  ```
115
- $ bundle exec bin/heroku-api
116
- Usage: heroku-api <command> [<parameter> [...]] [<body>]
117
-
118
- Help topics, type "heroku-api help <topic>" for more details:
119
-
120
- account-feature:info Info for an existing account feature.
121
- account-feature:list List existing account features.
122
- account-feature:update Update an existing account feature.
123
- account:change-email Change Email for account.
124
- account:change-password Change Password for account.
125
- account:info Info for account.
126
- account:update Update account.
127
- addon-service:info Info for existing addon-service.
128
- addon-service:list List existing addon-services.
129
- addon:create Create a new add-on.
130
- --- 8< --- snip --- 8< ---
55
+ bin/heroics-generator \
56
+ -c "~/.heroics/myapp" \
57
+ MyApp \
58
+ schema.json \
59
+ https://api.myapp.com > client.rb
131
60
  ```
132
61
 
133
- Use the `help` command to learn about commands:
62
+ `~` will automatically be expanded to the user's home directory. Be sure to
63
+ wrap such paths in quotes to avoid the shell expanding it to the directory you
64
+ built the client in.
134
65
 
135
- ```
136
- $ bundle exec bin/heroku-api help app:create
137
- Usage: heroku-api app:create <body>
138
-
139
- Description:
140
- Create a new app.
141
-
142
- Body example:
143
- {
144
- "name": "example",
145
- "region": "",
146
- "stack": ""
147
- }
148
- ```
66
+ ### Generating API documentation
149
67
 
150
- In addition to being a fun way to play with your API it also gives you
151
- the basic information you need to use the same command from Ruby:
68
+ The generated client has [Yard](http://yardoc.org/)-compatible docstrings.
69
+ You can generate documentation using `yardoc`:
152
70
 
153
- ```ruby
154
- client.app.create({'name' => 'example',
155
- 'region' => '',
156
- 'stack' => ''})
157
71
  ```
158
-
159
- ### Command arguments
160
-
161
- Commands that take arguments will list them in help output from the
162
- client.
163
-
72
+ yard doc -m markdown client.rb
164
73
  ```
165
- $ bundle exec bin/heroku-api help app:info
166
- Usage: heroku-api app:info <id|name>
167
74
 
168
- Description:
169
- Info for existing app.
170
- ```
171
-
172
- This command needs an app's UUID or name:
75
+ This will generate HTML in the `docs` directory. Note that Yard creates an
76
+ `_index.html` page that doesn't appear to be compatible with GitHub Pages. If
77
+ you're hosting your content there you can change the links:
173
78
 
174
- ```ruby
175
- info = client.app.info('sushi')
176
79
  ```
177
-
178
- Some commands need arguments as well as a body. In such cases, pass
179
- the arguments first with the body at the end.
180
-
181
- ### Using the Heroku API
182
-
183
- Heroics comes with a builtin `heroku-api` program that serves as an
184
- example and makes it easy to play with the [Heroku Platform API](https://devcenter.heroku.com/articles/platform-api-reference).
80
+ cd docs
81
+ sed -e 's/_index\.html/index\.html/g' -i `grep _index.html * -rl`
82
+ ```
185
83
 
186
84
  ### Handling failures
187
85
 
188
- The client uses [Excon](https://github.com/geemus/excon) under the hood and raises Excon errors when
189
- failures occur.
86
+ The client uses [Excon](https://github.com/geemus/excon) under the hood and
87
+ raises Excon errors when failures occur.
190
88
 
191
89
  ```ruby
192
90
  begin
193
91
  client.app.create({'name' => 'example'})
194
- rescue Excon::Errors::Forbidden => e
195
- puts e
92
+ rescue Excon::Errors::Forbidden => error
93
+ puts error
196
94
  end
197
95
  ```
198
96
 
@@ -3,20 +3,37 @@
3
3
  require 'optparse'
4
4
  require 'heroics'
5
5
 
6
- options = {}
6
+ options = {headers: {}, cache_path: nil}
7
7
  option_parser = OptionParser.new do |opts|
8
8
  opts.banner = 'Usage: heroics-generate module_name schema_filename url'
9
- opts.on( '-h', '--help', 'Display this screen' ) do
9
+
10
+ opts.on('-h', '--help', 'Display this screen') do
10
11
  puts opts
11
12
  exit
12
13
  end
14
+
15
+ opts.on('-H', '--header [HEADER]',
16
+ 'Include header with all requests') do |header|
17
+ parts = header.split(':', 0)
18
+ options[:headers][parts[0]] = parts[1].strip
19
+ end
20
+
21
+ opts.on('-c', '--cache-dir [PATH]',
22
+ 'Content cache directory (~ is automatically expanded)') do |path|
23
+ options[:cache_path] = path.sub('~', '#{Dir.home}')
24
+ end
13
25
  end
14
26
 
15
27
  option_parser.parse!
16
- module_name, schema_filename, url = ARGV
17
- schema = Heroics::Schema.new(MultiJson.decode(File.read(schema_filename)))
18
- options = {
19
- default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'},
20
- cache: 'Moneta.new(:File, dir: "#{Dir.home}/.heroics/platform-api")'
21
- }
22
- puts Heroics.generate_client(module_name, schema, url, options)
28
+ if ARGV.length != 3
29
+ puts option_parser
30
+ else
31
+ module_name, schema_filename, url = ARGV
32
+ schema = Heroics::Schema.new(MultiJson.decode(File.read(schema_filename)))
33
+ cache = 'Moneta.new(:Memory)'
34
+ if options[:cache_path]
35
+ cache = "Moneta.new(:File, dir: \"#{options[:cache_path]}\")"
36
+ end
37
+ options = {default_headers: options[:headers], cache: cache}
38
+ puts Heroics.generate_client(module_name, schema, url, options)
39
+ end
@@ -10,9 +10,9 @@ Gem::Specification.new do |spec|
10
10
  spec.version = Heroics::VERSION
11
11
  spec.authors = ['geemus', 'jkakar']
12
12
  spec.email = ['geemus@gmail.com', 'jkakar@kakar.ca']
13
- spec.description = 'A Ruby client for HTTP APIs described using a JSON schema'
14
- spec.summary = 'A Ruby client for HTTP APIs described using a JSON schema'
15
- spec.homepage = ''
13
+ spec.description = 'A Ruby client generator for HTTP APIs described with a JSON schema'
14
+ spec.summary = 'A Ruby client generator for HTTP APIs described with a JSON schema'
15
+ spec.homepage = 'https://github.com/interagent/heroics'
16
16
  spec.license = 'MIT'
17
17
 
18
18
  spec.files = `git ls-files`.split($/)
@@ -79,4 +79,28 @@ module Heroics
79
79
  options[:default_headers].merge!({"Authorization" => authorization})
80
80
  client_from_schema(schema, url, options)
81
81
  end
82
+
83
+ # Create an HTTP client with Token credentials from a JSON schema.
84
+ #
85
+ # @param oauth_token [String] The token to pass using the `Bearer`
86
+ # authorization mechanism.
87
+ # @param schema [Schema] The JSON schema to build an HTTP client for.
88
+ # @param url [String] The URL the generated client should use when making
89
+ # requests.
90
+ # @param options [Hash] Configuration for links. Possible keys include:
91
+ # - default_headers: Optionally, a set of headers to include in every
92
+ # request made by the client. Default is no custom headers.
93
+ # - cache: Optionally, a Moneta-compatible cache to store ETags. Default
94
+ # is no caching.
95
+ # @return [Client] A client with resources and links from the JSON schema.
96
+ def self.token_client_from_schema(token, schema, url, options={})
97
+ authorization = "Token token=#{token}"
98
+ # Don't mutate user-supplied data.
99
+ options = Marshal.load(Marshal.dump(options))
100
+ if !options.has_key?(:default_headers)
101
+ options[:default_headers] = {}
102
+ end
103
+ options[:default_headers].merge!({"Authorization" => authorization})
104
+ client_from_schema(schema, url, options)
105
+ end
82
106
  end
@@ -1,3 +1,3 @@
1
1
  module Heroics
2
- VERSION = '0.0.7'
2
+ VERSION = '0.0.8'
3
3
  end
@@ -27,8 +27,8 @@ module <%= @module_name %>
27
27
  end
28
28
  cache = <%= @cache %>
29
29
  options = {
30
- options: {default_headers: default_headers,
31
- cache: cache}
30
+ default_headers: default_headers,
31
+ cache: cache
32
32
  }
33
33
  client = Heroics.client_from_schema(SCHEMA, url.to_s, options)
34
34
  Client.new(client)
@@ -49,10 +49,32 @@ module <%= @module_name %>
49
49
  end
50
50
  cache = <%= @cache %>
51
51
  options = {
52
- options: {default_headers: default_headers,
53
- cache: cache}
52
+ default_headers: default_headers,
53
+ cache: cache
54
54
  }
55
- client = Heroics.client_from_schema(oauth_token, SCHEMA, url, options)
55
+ client = Heroics.oauth_client_from_schema(oauth_token, SCHEMA, url, options)
56
+ Client.new(client)
57
+ end
58
+
59
+ # Get a Client configured to use Token authentication.
60
+ #
61
+ # @param token [String] The token to use with the API.
62
+ # @param headers [Hash<String,String>] Optionally, custom to headers to
63
+ # include with every response.
64
+ # @return [Client] A client configured to use the API with OAuth
65
+ # authentication.
66
+ def self.connect_token(token, headers=nil)
67
+ url = "<%= @url %>"
68
+ default_headers = <%= @default_headers %>
69
+ unless headers.nil?
70
+ default_headers.merge!(headers)
71
+ end
72
+ cache = <%= @cache %>
73
+ options = {
74
+ default_headers: default_headers,
75
+ cache: cache
76
+ }
77
+ client = Heroics.token_client_from_schema(token, SCHEMA, url, options)
56
78
  Client.new(client)
57
79
  end
58
80
 
@@ -185,3 +185,51 @@ class OAuthClientFromSchemaTest < MiniTest::Unit::TestCase
185
185
  assert_equal(body, client.resource.list)
186
186
  end
187
187
  end
188
+
189
+ class TokenClientFromSchemaTest < MiniTest::Unit::TestCase
190
+ include ExconHelper
191
+
192
+ # token_client_from_schema injects an Authorization header, built from the
193
+ # specified token, into the default header options.
194
+ def test_token_client_from_schema
195
+ body = {'Hello' => 'World!'}
196
+ Excon.stub(method: :get) do |request|
197
+ assert_equal(
198
+ 'Token token=c55ef0d8-40b6-4759-b1bf-4a6f94190a66',
199
+ request[:headers]['Authorization'])
200
+ Excon.stubs.pop
201
+ {status: 200, headers: {'Content-Type' => 'application/json'},
202
+ body: MultiJson.dump(body)}
203
+ end
204
+
205
+ token = 'c55ef0d8-40b6-4759-b1bf-4a6f94190a66'
206
+ schema = Heroics::Schema.new(SAMPLE_SCHEMA)
207
+ client = Heroics.token_client_from_schema(token, schema,
208
+ 'https://example.com')
209
+ assert_equal(body, client.resource.list)
210
+ end
211
+
212
+ # token_client_from_schema doesn't mutate the options object, and in
213
+ # particular, it doesn't mutate the :default_headers Hash in that object.
214
+ def test_token_client_from_schema_with_options
215
+ body = {'Hello' => 'World!'}
216
+ Excon.stub(method: :get) do |request|
217
+ assert_equal('application/vnd.heroku+json; version=3',
218
+ request[:headers]['Accept'])
219
+ assert_equal(
220
+ 'Token token=c55ef0d8-40b6-4759-b1bf-4a6f94190a66',
221
+ request[:headers]['Authorization'])
222
+ Excon.stubs.pop
223
+ {status: 200, headers: {'Content-Type' => 'application/json'},
224
+ body: MultiJson.dump(body)}
225
+ end
226
+
227
+ token = 'c55ef0d8-40b6-4759-b1bf-4a6f94190a66'
228
+ options = {
229
+ default_headers: {'Accept' => 'application/vnd.heroku+json; version=3'}}
230
+ schema = Heroics::Schema.new(SAMPLE_SCHEMA)
231
+ client = Heroics.token_client_from_schema(token, schema,
232
+ 'https://example.com', options)
233
+ assert_equal(body, client.resource.list)
234
+ end
235
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - geemus
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-29 00:00:00.000000000 Z
12
+ date: 2014-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -137,7 +137,7 @@ dependencies:
137
137
  - - '>='
138
138
  - !ruby/object:Gem::Version
139
139
  version: '0'
140
- description: A Ruby client for HTTP APIs described using a JSON schema
140
+ description: A Ruby client generator for HTTP APIs described with a JSON schema
141
141
  email:
142
142
  - geemus@gmail.com
143
143
  - jkakar@kakar.ca
@@ -180,7 +180,7 @@ files:
180
180
  - test/resource_test.rb
181
181
  - test/schema_test.rb
182
182
  - test/version_test.rb
183
- homepage: ''
183
+ homepage: https://github.com/interagent/heroics
184
184
  licenses:
185
185
  - MIT
186
186
  metadata: {}
@@ -203,5 +203,5 @@ rubyforge_project:
203
203
  rubygems_version: 2.0.14
204
204
  signing_key:
205
205
  specification_version: 4
206
- summary: A Ruby client for HTTP APIs described using a JSON schema
206
+ summary: A Ruby client generator for HTTP APIs described with a JSON schema
207
207
  test_files: []