artemis 0.1.0 → 0.2.0

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
  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 %>