artemis 0.1.0 → 0.2.0

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
  SHA256:
3
- metadata.gz: c44b0b7dd0ed93d3c8c64f8a63dbaae919c90a04eee6a476d83add0253ffbb39
4
- data.tar.gz: f220a99f21d8bc7f24f1ae2dd1140f975707c6e26f74951e703a34edcdbd93c0
3
+ metadata.gz: ac727e89f6d2c0845b888ea9eeb526bf2607689fa268c9f815b9af3c25c83d72
4
+ data.tar.gz: 1cb2c9c3de64e95b729f579dfb4a8bd93a07d6ac4732647bf7aa94a360a6624a
5
5
  SHA512:
6
- metadata.gz: fc1ec085d1a695a683268067a5df8c63c8bc4aa5033527d458fc4cf5071e29bfc432ae8badeb132127d27703c5df384e5be8e2893c3335a9252d8a36abb193a0
7
- data.tar.gz: ca037098da82ff0dbd97f0232319ecebb75714c455dc7ca0b59ea666ba465b3ccf9641b97e1f4390e29ba0a8e1c9f44ad3faa78df82293e68967deedfb063d54
6
+ metadata.gz: 041b006e10af9271e6cb024f2acfdc1597969ad44ccf371235a12f95c2464afac66110967db926ece6df3c46c3161b3b3f54436ea276b0362234c27f13e5933e
7
+ data.tar.gz: 0daaea8bebcbf4ea6c9225781f591b4cd069aa6517dacb09043500b29357c1140d4169ed00e55046003702489addbfea60ef7703bc607692186ef61c7d94c0ac
@@ -0,0 +1,15 @@
1
+ ## Unreleased
2
+
3
+ * Add a new entry here
4
+ * [#43](https://github.com/yuki24/artemis/pull/43): Keep persistent connections open for 30 minutes
5
+ * [#42](https://github.com/yuki24/artemis/pull/42): Allow for setting up the test adapter without `url`
6
+ * [#41](https://github.com/yuki24/artemis/pull/41): Add a mutation generator
7
+ * [#40](https://github.com/yuki24/artemis/pull/40): Add a query generator
8
+ * [#39](https://github.com/yuki24/artemis/pull/39): Installer now adds a new service if config/graphql.yml is present
9
+
10
+ ## [v0.1.0: First release!](https://github.com/yuki24/artemis/tree/v0.1.0)
11
+
12
+ _<sup>released at 2018-10-16 20:57:51 UTC</sup>_
13
+
14
+ First release of Artemis! <g-emoji class="g-emoji" alias="tada" fallback-src="https://assets-cdn.github.com/images/icons/emoji/unicode/1f389.png">&#127881;</g-emoji>
15
+
data/README.md CHANGED
@@ -6,7 +6,9 @@
6
6
  once in production and it'll never affect runtime performance. Comes with options that enable persistent connections
7
7
  and even HTTP/2.0, the next-gen high-performance protocol.
8
8
 
9
- ### Getting started
9
+ <img width="24" height="24" src="https://avatars1.githubusercontent.com/u/541332?s=48&amp;v=4"> Battled-tested at [Artsy](https://www.artsy.net)
10
+
11
+ ## Getting started
10
12
 
11
13
  Add this line to your application's Gemfile:
12
14
 
@@ -18,87 +20,72 @@ And then execute:
18
20
 
19
21
  $ bundle
20
22
 
21
- Once you run `bundle install` on your Rails app, you will be able to run the following command:
23
+ Once you run `bundle install` on your Rails app, run the install command:
22
24
 
23
25
 
24
26
  ```sh
25
27
  $ rails g artemis:install artsy https://metaphysics-production.artsy.net/
26
28
  ```
27
29
 
28
- It is common that a GraphQL server requires an OAuth access token. If it is the case, use the `--authorization` option
29
- to assign a token so the installer can properly download the GraphQL schema for the service:
30
+ You could also use the `--authorization` option to assign a token so the installer can download the GraphQL schema:
30
31
 
31
32
  ```sh
32
33
  $ rails g artemis:install github https://api.github.com/graphql --authorization 'token ...'
33
34
  ```
34
35
 
35
- ## The convention
36
+ ### Generating your first query
36
37
 
37
- Artemis assumes that the files related to GraphQL are organized with the following structure:
38
+ Artemis comes with a query generator. For exmaple, you could use the query generator to generate a query stub for `artist`:
38
39
 
39
- ```
40
- ├──app/operations
41
- │   ├── artsy
42
- │   │   ├── _artist_fragment.graphql
43
- │   │   ├── artwork.graphql
44
- │   │   ├── artist.graphql
45
- │   │   └── artists.graphql
46
- │   └── artsy.rb
47
- ├──config/graphql.yml
48
- └──vendor/graphql/schema/artsy.json
40
+ ```sh
41
+ $ rails g artemis:query artist
49
42
  ```
50
43
 
51
- ## Examples
44
+ Then this will generate:
52
45
 
53
- ```yml
54
- # config/graphql.yml
55
- development:
56
- artsy:
57
- url: https://metaphysics-production.artsy.net/
46
+ ```graphql
47
+ # app/operations/artist.graphql
48
+ query($id: String!) {
49
+ artist(id: $id) {
50
+ # Add fields here...
51
+ }
52
+ }
58
53
  ```
59
54
 
55
+ Then you could the class method that has the matching name `artist`:
56
+
60
57
  ```ruby
61
- # app/queries/artsy.rb
62
- class Artsy < Artemis::Client
63
- end
58
+ Artsy.artist(id: "pablo-picasso")
59
+ # => makes a GraphQL query that's in app/operations/artist.graphql
64
60
  ```
65
61
 
66
- ```graphql
67
- # app/queries/artsy/artwork.graphql
68
- query($id: String!) {
69
- artwork(id: $id) {
70
- title
71
- }
72
- }
62
+ You can also specify a file name:
73
63
 
74
- # app/queries/artsy/me.graphql
75
- query {
76
- me {
77
- name
78
- }
79
- }
64
+ ```sh
65
+ $ rails g artemis:query artist artist_details_on_artwork
66
+ # => generates app/operations/artist_details_on_artwork.graphql
80
67
  ```
81
68
 
69
+ Then you can make a query in `artist_details_on_artwork.graphql` with:
70
+
82
71
  ```ruby
83
- results = Artsy.artwork(id: "andy-warhol-john-wayne-1986-number-377-cowboys-and-indians")
84
- results.data
85
- # => {
86
- # "data": {
87
- # "artwork": {
88
- # "title": "John Wayne, 1986 (#377, Cowboys & Indians)"
89
- # }
90
- # }
91
- # }
92
-
93
- results = Artsy.with_context(headers: { "X-ACCESS-TOKEN": "..." }).me
94
- results.data
95
- # => {
96
- # "data": {
97
- # "me": {
98
- # "name": "Yuki Nishijima"
99
- # }
100
- # }
101
- # }
72
+ Artsy.artist_details_on_artwork(id: "pablo-picasso")
73
+ ```
74
+
75
+ ## The convention
76
+
77
+ Artemis assumes that the files related to GraphQL are organized in a certain way. For example, a service that talks to Artsy's GraphQL API could have the following structure:
78
+
79
+ ```
80
+ ├──app/operations
81
+ │   ├── artsy
82
+ │   │   ├── _artist_fragment.graphql
83
+ │   │   ├── artwork.graphql
84
+ │   │   ├── artist.graphql
85
+ │   │   └── artists.graphql
86
+ │   └── artsy.rb
87
+ ├──config/graphql.yml
88
+ └──vendor/graphql/schema/artsy.json
102
89
  ```
103
90
 
104
91
  ## Callbacks
@@ -149,11 +136,20 @@ There are four adapter options available. Choose the adapter that best fits on y
149
136
 
150
137
  | Adapter | Protocol | Keep-alive | Performance | Dependencies |
151
138
  | ---------------------- | ------------------------ | ----------- | ----------- | ------------ |
152
- | `:curb` | HTTP/1.1, **HTTP/2.0** | **Yes** | **Fastest** | [`curb 0.9.6+`](curb)<br>[`libcurl 7.64.0+`](curl)<br>[`nghttp2 1.0.0+`](nghttp)
139
+ | `:curb` | HTTP/1.1, **HTTP/2.0** | **Yes** | **Fastest** | [`curb 0.9.6+`][curb]<br>[`libcurl 7.64.0+`][curl]<br>[`nghttp2 1.0.0+`][nghttp]
153
140
  | `:net_http` (default) | HTTP/1.1 only | No | Slow | **None**
154
- | `:net_http_persistent` | HTTP/1.1 only | **Yes** | **Fast** | [`net-http-persistent 3.0.0+`](nhp)
141
+ | `:net_http_persistent` | HTTP/1.1 only | **Yes** | **Fast** | [`net-http-persistent 3.0.0+`][nhp]
155
142
  | `:test` | N/A (See Testing)
156
143
 
144
+ ## Rake tasks
145
+
146
+ Artemis also adds a useful `rake graphql:schema:update` rake task that downloads the GraphQL schema using the
147
+ `Introspection` query.
148
+
149
+ | Task Name | Options | Description |
150
+ | ---------------------------- | --------- | ------------|
151
+ | `graphql:schema:update` | `SERVICE`: Service name the schema is downloaded from<br>`AUTHORIZATION`: HTTTP `Authroization` header value used to download the schema| Downloads and saves the GraphQL schema
152
+
157
153
  ## Testing
158
154
 
159
155
  **The testing support is incomplete, but there are some examples [available in Artemis' client spec](https://github.com/yuki24/artemis/blob/74095f3acb050e87251439aed5f8b17778ffdd06/spec/client_spec.rb#L36-L54).**
@@ -176,6 +172,7 @@ The gem is available as open source under the terms of the [MIT License](https:/
176
172
 
177
173
  Everyone interacting in the Artemis project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/artemis/blob/master/CODE_OF_CONDUCT.md).
178
174
 
175
+ [curb]: https://rubygems.org/gems/curb
179
176
  [curl]: https://curl.haxx.se/docs/http2.html
180
177
  [nghttp]: https://nghttp2.org/
181
178
  [nhp]: https://rubygems.org/gems/net-http-persistent
data/Rakefile CHANGED
@@ -2,13 +2,20 @@ require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
  require 'rspec/core/rake_task'
4
4
 
5
+ TESTS_IN_ISOLATION = ['test/railtie_test.rb', 'test/rake_tasks_test.rb']
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.test_files = FileList['test/**/*_test.rb'] - TESTS_IN_ISOLATION
10
+ t.warning = false
11
+ end
12
+
5
13
  Rake::TestTask.new('test:isolated') do |t|
6
14
  t.libs << "test"
7
- t.libs << "lib"
8
- t.test_files = FileList['test/**/*_test.rb']
15
+ t.test_files = TESTS_IN_ISOLATION
9
16
  t.warning = false
10
17
  end
11
18
 
12
19
  RSpec::Core::RakeTask.new(:spec)
13
20
 
14
- task default: ['spec', 'test:isolated']
21
+ task default: ['spec', 'test', 'test:isolated']
@@ -6,8 +6,8 @@ require "artemis/version"
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "artemis"
8
8
  spec.version = Artemis::VERSION
9
- spec.authors = ["Yuki Nishijima"]
10
- spec.email = ["yk.nishijima@gmail.com"]
9
+ spec.authors = ["Jon Allured", "Yuki Nishijima"]
10
+ spec.email = ["jon.allured@gmail.com", "yk.nishijima@gmail.com"]
11
11
  spec.summary = %q{GraphQL on Rails}
12
12
  spec.description = %q{GraphQL client on Rails + Convention over Configuration = ❤️}
13
13
  spec.homepage = "https://github.com/yuki24/artemis"
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/object/blank'
3
4
  require 'graphql/client/http'
4
5
 
5
6
  module Artemis
@@ -10,6 +11,8 @@ module Artemis
10
11
  EMPTY_HEADERS = {}.freeze
11
12
 
12
13
  def initialize(uri, service_name: , timeout: , pool_size: )
14
+ raise ArgumentError, "url is required (given `#{uri.inspect}')" if uri.blank?
15
+
13
16
  super(uri) # Do not pass in the block to avoid getting #headers and #connection overridden.
14
17
 
15
18
  @service_name = service_name.to_s
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'delegate'
4
4
 
5
+ require 'active_support/core_ext/numeric/time'
5
6
  require 'net/http/persistent'
6
7
 
7
8
  require 'artemis/adapters/net_http_adapter'
@@ -17,6 +18,7 @@ module Artemis
17
18
  @raw_connection = Net::HTTP::Persistent.new(name: service_name, pool_size: pool_size)
18
19
  @raw_connection.open_timeout = timeout
19
20
  @raw_connection.read_timeout = timeout
21
+ @raw_connection.idle_timeout = 30.minutes.to_i # TODO: Make it configurable
20
22
 
21
23
  @_connection = ConnectionWrapper.new(@raw_connection, uri)
22
24
  end
@@ -28,7 +30,7 @@ module Artemis
28
30
  _connection
29
31
  end
30
32
 
31
- class ConnectionWrapper < SimpleDelegator
33
+ class ConnectionWrapper < SimpleDelegator #:nodoc:
32
34
  def initialize(obj, url)
33
35
  super(obj)
34
36
 
@@ -44,13 +44,13 @@ module Artemis
44
44
  # }
45
45
  #
46
46
  # # app/operations/github.rb
47
- # class GitHub < Artemis::Client
47
+ # class Github < Artemis::Client
48
48
  # end
49
49
  #
50
- # github = GitHub.new
50
+ # github = Github.new
51
51
  # github.user(id: 'yuki24').data.user.name # => "Yuki Nishijima"
52
52
  #
53
- # github = GitHub.new(context: { headers: { Authorization: "bearer ..." } })
53
+ # github = Github.new(context: { headers: { Authorization: "bearer ..." } })
54
54
  # github.user(id: 'yuki24').data.user.name # => "Yuki Nishijima"
55
55
  #
56
56
  def initialize(context = {})
@@ -60,12 +60,65 @@ module Artemis
60
60
  class << self
61
61
  delegate :query_paths, :default_context, :query_paths=, :default_context=, to: :config
62
62
 
63
+ # Creates a new instance of the GraphQL client for the service.
64
+ #
65
+ # # app/operations/github/user.graphql
66
+ # query($id: String!) {
67
+ # user(login: $id) {
68
+ # name
69
+ # }
70
+ # }
71
+ #
72
+ # # app/operations/github.rb
73
+ # class Github < Artemis::Client
74
+ # end
75
+ #
76
+ # github = Github.new
77
+ # github.user(id: 'yuki24').data.user.name # => "Yuki Nishijima"
78
+ #
79
+ # github = Github.new(context: { headers: { Authorization: "bearer ..." } })
80
+ # github.user(id: 'yuki24').data.user.name # => "Yuki Nishijima"
81
+ #
63
82
  alias with_context new
64
83
 
84
+ # Returns the registered meta data (generally present in +config/graphql.yml+) for the client.
85
+ #
86
+ # # config/graphql.yml
87
+ # development:
88
+ # github:
89
+ # url: https://api.github.com/graphql
90
+ # adapter: :net_http
91
+ #
92
+ # # app/operations/github.rb
93
+ # class Github < Artemis::Client
94
+ # end
95
+ #
96
+ # Github.endpoint.url # => "https://api.github.com/graphql"
97
+ # Github.endpoint.adapter # => :net_http
98
+ #
65
99
  def endpoint
66
100
  Artemis::GraphQLEndpoint.lookup(name)
67
101
  end
68
102
 
103
+ # Instantiates a new instance of +GraphQL::Client+ for the service.
104
+ #
105
+ # # app/operations/github/user.graphql
106
+ # query($id: String!) {
107
+ # user(login: $id) {
108
+ # name
109
+ # }
110
+ # }
111
+ #
112
+ # # app/operations/github.rb
113
+ # class Github < Artemis::Client
114
+ # end
115
+ #
116
+ # client = Github.instantiate_client
117
+ # client.query(Github::User, arguments: { id: 'yuki24' }) # makes a Graphql request
118
+ #
119
+ # client = Github.instantiate_client(context: { headers: { Authorization: "bearer ..." } })
120
+ # client.query(Github::User, arguments: { id: 'yuki24' }) # makes a Graphql request with Authorization header
121
+ #
69
122
  def instantiate_client(context = {})
70
123
  ::GraphQL::Client.new(schema: endpoint.schema, execute: connection(context))
71
124
  end
@@ -73,7 +126,7 @@ module Artemis
73
126
  # Defines a callback that will get called right before the
74
127
  # client's execute method is executed.
75
128
  #
76
- # class GitHub < Artemis::Client
129
+ # class Github < Artemis::Client
77
130
  #
78
131
  # before_execute do |document, operation_name, variables, context|
79
132
  # Analytics.log(operation_name, variables, context[:user_id])
@@ -89,7 +142,7 @@ module Artemis
89
142
  # Defines a callback that will get called right after the
90
143
  # client's execute method has finished.
91
144
  #
92
- # class GitHub < Artemis::Client
145
+ # class Github < Artemis::Client
93
146
  #
94
147
  # after_execute do |data, errors, extensions|
95
148
  # if errors.present?
@@ -136,7 +189,6 @@ module Artemis
136
189
  end
137
190
  alias load_query load_constant
138
191
 
139
- # @api private
140
192
  def connection(context = {})
141
193
  Executor.new(endpoint.connection, callbacks, default_context.deep_merge(context))
142
194
  end
@@ -157,15 +209,12 @@ module Artemis
157
209
  end
158
210
  end
159
211
 
160
- # @api private
161
- def respond_to_missing?(method_name, *_, &block)
212
+ def respond_to_missing?(method_name, *_, &block) #:nodoc:
162
213
  resolve_graphql_file_path(method_name) || super
163
214
  end
164
215
 
165
- Callbacks = Struct.new(:before_callbacks, :after_callbacks)
166
-
167
- private_constant :Callbacks
168
-
216
+ # Returns a +Callbacks+ collection object that implements the interface for the +Executor+ object.
217
+ #
169
218
  # @api private
170
219
  def callbacks
171
220
  Callbacks.new(config.before_callbacks, config.after_callbacks)
@@ -194,8 +243,7 @@ module Artemis
194
243
  end
195
244
  end
196
245
 
197
- # @api private
198
- def respond_to_missing?(method_name, *_, &block)
246
+ def respond_to_missing?(method_name, *_, &block) #:nodoc:
199
247
  self.class.resolve_graphql_file_path(method_name) || super
200
248
  end
201
249
 
@@ -213,33 +261,40 @@ module Artemis
213
261
  end
214
262
  RUBY
215
263
  end
216
- end
217
264
 
218
- # @api private
219
- class Executor < SimpleDelegator
220
- def initialize(connection, callbacks, default_context)
221
- super(connection)
222
-
223
- @callbacks = callbacks
224
- @default_context = default_context
225
- end
265
+ # Internal collection object that holds references to the callback blocks.
266
+ #
267
+ # @api private
268
+ Callbacks = Struct.new(:before_callbacks, :after_callbacks) #:nodoc:
226
269
 
227
- def execute(document:, operation_name: nil, variables: {}, context: {})
228
- _context = @default_context.deep_merge(context)
270
+ # Wrapper object around the adapter that wires up callbacks.
271
+ #
272
+ # @api private
273
+ class Executor < SimpleDelegator
274
+ def initialize(connection, callbacks, default_context) #:nodoc:
275
+ super(connection)
229
276
 
230
- @callbacks.before_callbacks.each do |callback|
231
- callback.call(document, operation_name, variables, _context)
277
+ @callbacks = callbacks
278
+ @default_context = default_context
232
279
  end
233
280
 
234
- response = __getobj__.execute(document: document, operation_name: operation_name, variables: variables, context: _context)
281
+ def execute(document:, operation_name: nil, variables: {}, context: {}) #:nodoc:
282
+ _context = @default_context.deep_merge(context)
235
283
 
236
- @callbacks.after_callbacks.each do |callback|
237
- callback.call(response['data'], response['errors'], response['extensions'])
238
- end
284
+ @callbacks.before_callbacks.each do |callback|
285
+ callback.call(document, operation_name, variables, _context)
286
+ end
239
287
 
240
- response
288
+ response = __getobj__.execute(document: document, operation_name: operation_name, variables: variables, context: _context)
289
+
290
+ @callbacks.after_callbacks.each do |callback|
291
+ callback.call(response['data'], response['errors'], response['extensions'])
292
+ end
293
+
294
+ response
295
+ end
241
296
  end
242
- end
243
297
 
244
- private_constant :Executor
298
+ private_constant :Callbacks, :Executor
299
+ end
245
300
  end
@@ -27,11 +27,18 @@ module Artemis
27
27
  def register!(service_name, configurations)
28
28
  ENDPOINT_INSTANCES[service_name.to_s.underscore] = new(service_name.to_s, configurations.symbolize_keys)
29
29
  end
30
+
31
+ ##
32
+ # Returns the registered services as an array.
33
+ #
34
+ def registered_services
35
+ ENDPOINT_INSTANCES.keys
36
+ end
30
37
  end
31
38
 
32
39
  attr_reader :name, :url, :adapter, :timeout, :schema_path, :pool_size
33
40
 
34
- def initialize(name, url: , adapter: :net_http, timeout: 30, schema_path: nil, pool_size: 5)
41
+ def initialize(name, url: nil, adapter: :net_http, timeout: 10, schema_path: nil, pool_size: 25)
35
42
  @name, @url, @adapter, @timeout, @schema_path, @pool_size = name.to_s, url, adapter, timeout, schema_path, pool_size
36
43
 
37
44
  @mutex_for_schema = Mutex.new
@@ -1,3 +1,3 @@
1
1
  module Artemis
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,7 +2,7 @@ Description:
2
2
  Generates a client stub and config files and downloads the schema from the given endpoint.
3
3
 
4
4
  Example:
5
- rails generate install Artsy https://metaphysics-production.artsy.net
5
+ rails generate artemis:install Artsy https://metaphysics-production.artsy.net
6
6
 
7
7
  This will create:
8
8
  app/operations/artsy.rb
@@ -17,6 +17,24 @@ class Artemis::InstallGenerator < Rails::Generators::NamedBase
17
17
  in_root do
18
18
  if behavior == :invoke && !File.exist?(config_file_name)
19
19
  template "graphql.yml", config_file_name
20
+ else
21
+ inject_into_file config_file_name, <<-YAML, after: "development:\n"
22
+ #{file_name}:
23
+ <<: *default
24
+ url: #{endpoint_url}\n
25
+ YAML
26
+
27
+ inject_into_file config_file_name, <<-YAML, after: "test:\n", force: true
28
+ #{file_name}:
29
+ <<: *default
30
+ url: #{endpoint_url}\n
31
+ YAML
32
+
33
+ inject_into_file config_file_name, <<-YAML, after: "production:\n", force: true
34
+ #{file_name}:
35
+ <<: *default
36
+ url: #{endpoint_url}\n
37
+ YAML
20
38
  end
21
39
  end
22
40
  end
@@ -0,0 +1,34 @@
1
+ default: &default
2
+ # The underlying client library that actually makes an HTTP request.
3
+ # Available adapters are :net_http, :net_http_persistent, :curb, and :test.
4
+ #
5
+ # It is set to :net_http by default.
6
+ adapter: :net_http
7
+
8
+ # HTTP timeout set for the adapter in seconds. This will be set to both
9
+ # `read_timeout` and `write_timeout` and there is no way to configure them
10
+ # with a different value as of writing (PRs welcome!)
11
+ #
12
+ # It is set to 10 by default.
13
+ timeout: 10
14
+
15
+ # The number of keep-alive connections. The `:net_http` adapter will ignore
16
+ # this option.
17
+ #
18
+ # It is set to 25 by default.
19
+ pool_size: 25
20
+
21
+ development:
22
+ <%= file_name %>:
23
+ <<: *default
24
+ url: <%= endpoint_url %>
25
+
26
+ test:
27
+ <%= file_name %>:
28
+ <<: *default
29
+ url: <%= endpoint_url %>
30
+
31
+ production:
32
+ <%= file_name %>:
33
+ <<: *default
34
+ url: <%= endpoint_url %>
@@ -0,0 +1,27 @@
1
+ Description:
2
+ Generates a mutation stub.
3
+
4
+ rails g artemis:mutation MUTATION_TYPE [FILE_NAME]
5
+
6
+ Example:
7
+ rails g artemis:mutation followArtist
8
+
9
+ This will create:
10
+ app/operations/artsy.rb
11
+ app/operations/artsy/follow_artist.graphql
12
+
13
+ The GraphQL file name could be specified by giving the third argument:
14
+
15
+ rails g artemis:mutation followArtist follow_artist_on_artwork
16
+
17
+ This will create:
18
+ app/operations/artsy.rb
19
+ app/operations/artsy/follow_artist_on_artwork.graphql
20
+
21
+ If there are multiple services registered, the service could be specified with +--service+ option:
22
+
23
+ rails g artemis:mutation createProject --service github
24
+
25
+ This will create:
26
+ app/operations/github.rb
27
+ app/operations/github/create_project.graphql
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql/schema/finder'
4
+
5
+ class Artemis::MutationGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ argument :mutation_type, type: :string, required: true, banner: "Mutation type"
9
+ argument :graphql_file_name, type: :string, required: false, default: nil, banner: "The name of the GraphQL file to be generated"
10
+
11
+ class_option :service, type: :string, default: nil, aliases: "-A"
12
+
13
+ def generate_mutation_file
14
+ template "mutation.graphql", graphql_file_path
15
+ end
16
+
17
+ private
18
+
19
+ def mutation_name
20
+ mutation_type.underscore
21
+ end
22
+
23
+ def graphql_file_path
24
+ "app/operations/#{service_name.underscore}/#{graphql_file_name.presence || mutation_name}.graphql"
25
+ end
26
+
27
+ def arguments
28
+ target_mutation.arguments
29
+ end
30
+
31
+ def target_mutation
32
+ schema.find("Mutation").fields[mutation_type] ||
33
+ raise(GraphQL::Schema::Finder::MemberNotFoundError, "Could not find type `#{mutation_type}` in schema.")
34
+ end
35
+
36
+ def schema
37
+ service_name.camelize.constantize.endpoint.schema
38
+ end
39
+
40
+ def service_name
41
+ options['service'].presence || begin
42
+ services = Artemis::GraphQLEndpoint.registered_services
43
+
44
+ if services.size == 1
45
+ services.first
46
+ else
47
+ fail "Please specify a service name (available services: #{services.join(", ")}):\n\n" \
48
+ " rails g artemis:mutation #{mutation_type} #{graphql_file_name} --service SERVICE"
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ mutation<%= arguments.present? && "(#{ arguments.map {|name, type| "$#{name}: #{type.type}" }.join(", ") })" %> {
2
+ <%= target_mutation.name %><%= arguments.present? && "(#{ arguments.map {|name, type| "#{name}: $#{name}" }.join(", ") })" %> {
3
+ # Add fields here...
4
+ }
5
+ }
@@ -0,0 +1,27 @@
1
+ Description:
2
+ Generates a query stub.
3
+
4
+ rails g artemis:query QUERY_TYPE [FILE_NAME]
5
+
6
+ Example:
7
+ rails g artemis:query artist
8
+
9
+ This will create:
10
+ app/operations/artsy.rb
11
+ app/operations/artsy/artist.graphql
12
+
13
+ The GraphQL file name could be specified by giving the third argument:
14
+
15
+ rails g artemis:query artist artist_in_tooltip
16
+
17
+ This will create:
18
+ app/operations/artsy.rb
19
+ app/operations/artsy/artist_in_tooltip.graphql
20
+
21
+ If there are multiple services registered, the service could be specified with +--service+ option:
22
+
23
+ rails g artemis:query repository --service github
24
+
25
+ This will create:
26
+ app/operations/github.rb
27
+ app/operations/github/repository.graphql
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql/schema/finder'
4
+
5
+ class Artemis::QueryGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ argument :query_type, type: :string, required: true, banner: "Query type"
9
+ argument :graphql_file_name, type: :string, required: false, default: nil, banner: "The name of the GraphQL file to be generated"
10
+
11
+ class_option :service, type: :string, default: nil, aliases: "-A"
12
+
13
+ def generate_query_file
14
+ template "query.graphql", graphql_file_path
15
+ end
16
+
17
+ private
18
+
19
+ def query_name
20
+ query_type.underscore
21
+ end
22
+
23
+ def graphql_file_path
24
+ "app/operations/#{service_name.underscore}/#{graphql_file_name.presence || query_name}.graphql"
25
+ end
26
+
27
+ def arguments
28
+ target_query.arguments
29
+ end
30
+
31
+ def target_query
32
+ schema.find("Query").fields[query_type] ||
33
+ raise(GraphQL::Schema::Finder::MemberNotFoundError, "Could not find type `#{query_type}` in schema.")
34
+ end
35
+
36
+ def schema
37
+ service_name.camelize.constantize.endpoint.schema
38
+ end
39
+
40
+ def service_name
41
+ options['service'].presence || begin
42
+ services = Artemis::GraphQLEndpoint.registered_services
43
+
44
+ if services.size == 1
45
+ services.first
46
+ else
47
+ fail "Please specify a service name (available services: #{services.join(", ")}):\n\n" \
48
+ " rails g artemis:query #{query_type} #{graphql_file_name} --service SERVICE"
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ query<%= arguments.present? && "(#{ arguments.map {|name, type| "$#{name}: #{type.type}" }.join(", ") })" %> {
2
+ <%= target_query.name %><%= arguments.present? && "(#{ arguments.map {|name, type| "#{name}: $#{name}" }.join(", ") })" %> {
3
+ # Add fields here...
4
+ }
5
+ }
@@ -49,6 +49,14 @@ describe 'Adapters' do
49
49
  end
50
50
 
51
51
  shared_examples 'an adapter' do
52
+ describe '#initialize' do
53
+ it 'requires an url' do
54
+ expect do
55
+ adapter.class.new(nil, service_name: nil, timeout: 2, pool_size: 5)
56
+ end.to raise_error(ArgumentError, "url is required (given `nil')")
57
+ end
58
+ end
59
+
52
60
  describe '#execute' do
53
61
  it 'makes an actual HTTP request' do
54
62
  response = adapter.execute(
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: artemis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Jon Allured
7
8
  - Yuki Nishijima
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2018-10-16 00:00:00.000000000 Z
12
+ date: 2018-10-30 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: activesupport
@@ -138,6 +139,7 @@ dependencies:
138
139
  version: '3.8'
139
140
  description: GraphQL client on Rails + Convention over Configuration = ❤️
140
141
  email:
142
+ - jon.allured@gmail.com
141
143
  - yk.nishijima@gmail.com
142
144
  executables: []
143
145
  extensions: []
@@ -147,6 +149,7 @@ files:
147
149
  - ".rspec"
148
150
  - ".travis.yml"
149
151
  - Appraisals
152
+ - CHANGELOG.md
150
153
  - CODE_OF_CONDUCT.md
151
154
  - Gemfile
152
155
  - LICENSE.txt
@@ -155,6 +158,8 @@ files:
155
158
  - artemis.gemspec
156
159
  - bin/console
157
160
  - bin/setup
161
+ - doc/CHANGELOG.md.erb
162
+ - doc/changelog_generator.rb
158
163
  - gemfiles/.bundle/config
159
164
  - gemfiles/rails_42.gemfile
160
165
  - gemfiles/rails_50.gemfile
@@ -173,11 +178,16 @@ files:
173
178
  - lib/artemis/graphql_endpoint.rb
174
179
  - lib/artemis/railtie.rb
175
180
  - lib/artemis/version.rb
176
- - lib/generators/artemis/USAGE
177
- - lib/generators/artemis/install_generator.rb
178
- - lib/generators/artemis/templates/.gitkeep
179
- - lib/generators/artemis/templates/client.rb
180
- - lib/generators/artemis/templates/graphql.yml
181
+ - lib/generators/artemis/install/USAGE
182
+ - lib/generators/artemis/install/install_generator.rb
183
+ - lib/generators/artemis/install/templates/client.rb
184
+ - lib/generators/artemis/install/templates/graphql.yml
185
+ - lib/generators/artemis/mutation/USAGE
186
+ - lib/generators/artemis/mutation/mutation_generator.rb
187
+ - lib/generators/artemis/mutation/templates/mutation.graphql
188
+ - lib/generators/artemis/query/USAGE
189
+ - lib/generators/artemis/query/query_generator.rb
190
+ - lib/generators/artemis/query/templates/query.graphql
181
191
  - lib/tasks/artemis.rake
182
192
  - spec/adapters_spec.rb
183
193
  - spec/autoloading_spec.rb
File without changes
@@ -1,19 +0,0 @@
1
- default: &default
2
- adapter: :net_http
3
- timeout: 10
4
- pool_size: 25
5
-
6
- development:
7
- <%= file_name %>:
8
- <<: *default
9
- url: <%= endpoint_url %>
10
-
11
- test:
12
- <%= file_name %>:
13
- <<: *default
14
- url: <%= endpoint_url %>
15
-
16
- production:
17
- <%= file_name %>:
18
- <<: *default
19
- url: <%= endpoint_url %>