heroics 0.0.7 → 0.0.8

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: 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: []