Browse Source

Add documentation

Scott Walkinshaw 5 years ago
parent
commit
b87b06b851
3 changed files with 245 additions and 17 deletions
  1. 10 5
      README.md
  2. 191 0
      docs/graphql.md
  3. 44 12
      lib/shopify_api/graphql/task.rake

+ 10 - 5
README.md

@@ -346,15 +346,18 @@ gem install shopify_api_console
 
 ## GraphQL
 
-This library also supports Shopify's new [GraphQL API](https://help.shopify.com/api/graphql-admin-api)
-via a dependency on the [graphql-client](https://github.com/github/graphql-client) gem.
+Note: the GraphQL client has improved and changed in version 9.0. See the [client documentation](docs/graphql.md)
+for full usage details and a [migration guide](docs/graphql.md#migration-guide).
+
+This library also supports Shopify's [GraphQL Admin API](https://help.shopify.com/api/graphql-admin-api)
+via integration with the [graphql-client](https://github.com/github/graphql-client) gem.
 The authentication process (steps 1-5 under [Getting Started](#getting-started))
-is identical. Once your session is activated, simply construct a new graphql
-client and use `parse` and `query` as defined by
+is identical. Once your session is activated, simply access the GraphQL client
+and use `parse` and `query` as defined by
 [graphql-client](https://github.com/github/graphql-client#defining-queries).
 
 ```ruby
-client = ShopifyAPI::GraphQL.new
+client = ShopifyAPI::GraphQL.client
 
 SHOP_NAME_QUERY = client.parse <<-'GRAPHQL'
   {
@@ -368,6 +371,8 @@ result = client.query(SHOP_NAME_QUERY)
 result.data.shop.name
 ```
 
+[GraphQL client documentation](docs/graphql.md)
+
 ## Threadsafety
 
 ActiveResource is threadsafe as of version 4.1 (which works with Rails 4.x and above).

+ 191 - 0
docs/graphql.md

@@ -0,0 +1,191 @@
+# GraphQL client
+
+The `shopify_api` gem includes a full featured GraphQL client to interact with
+Shopify's [GraphQL Admin API](https://help.shopify.com/en/api/graphql-admin-api).
+GitHub's [graphql-client](https://github.com/github/graphql-client) is used as
+the underlying client and this library integrates it with our existing
+session, authentication, and API versioning features.
+
+## Example
+
+```ruby
+client = ShopifyAPI::GraphQL.client
+
+SHOP_NAME_QUERY = client.parse <<-'GRAPHQL'
+  {
+    shop {
+      name
+    }
+  }
+GRAPHQL
+
+result = client.query(SHOP_NAME_QUERY)
+result.data.shop.name
+```
+
+* [Getting started](#getting-started)
+* [Rails integration](#rails-integration)
+* [API versioning](#api-versioning)
+* [Initialization process](#initialization-process)
+* [Migration guide](#migration-guide)
+
+## Getting started
+
+1. [Dump the schema](#dump-the-schema)
+2. [Configure session/authencation](#sessions-and-authentication)
+3. [Make queries](#make-queries)
+
+### Dump the schema
+One of the main benefits of GraphQL is its [schema and type system](https://graphql.org/learn/schema/)
+which enables tools like graphql-client to ensure your queries are valid in development.
+
+So the first step in making GraphQL queries is having a local JSON file of Shopify's Admin schema.
+This gem provides a `shopify_api:graphql:dump` Rake task to make it as easy as possible:
+
+```bash
+$ rake shopify_api:graphql:dump SHOP_URL="https://API_KEY:PASSWORD@SHOP_NAME.myshopify.com" API_VERSION=2020-01
+```
+
+If successful `db/shopify_graphql_schemas/2020-01.json` will be created.
+
+You can either use private app authentication or an OAuth access token. Run `rake shopify_api:graphql:dump`
+to see full usage details.
+
+If you're using shopify_api in a Rails app, the default location for schema files is `db/shopify_graphql_schemas`.
+For non-Rails applications, the default is `shopify_graphql_schemas` in your project root.
+
+The schema path location can be changed via `ShopifyAPI::GraphQL.schema_location`:
+
+```ruby
+ShopifyAPI::GraphQL.schema_location = 'assets/schemas'
+```
+
+#### Updating schemas
+Each time you want to use a new API version, or update an existing one
+(such as the `unstable` version), simply run the Rake task again to overwrite the file.
+
+### Sessions and authentication
+The GraphQL client is designed to be integrated with the rest of shopify_api so
+all its features such as sessions, authentication, and API versioning work the
+exact same.
+
+If you've already been using the shopify_api gem in your application to make
+REST API calls then no other configuration is necessary.
+
+Steps 1-5 of our main [Getting started](https://github.com/Shopify/shopify_api#getting-started)
+section still apply for the GraphQL client as well.
+
+### Make queries
+Now that you've dumped a schema file and configured an authenticated session, you can make GraphQL API requests.
+graphql-client encourages all queries to be defined statically as constants:
+
+```ruby
+SHOP_NAME_QUERY = ShopifyAPI::GraphQL.client.parse <<-'GRAPHQL'
+  {
+    shop {
+      name
+    }
+  }
+GRAPHQL
+
+result = ShopifyAPI::GraphQL.client.query(SHOP_NAME_QUERY)
+result.data.shop.name
+```
+
+But we've also enabled its `allow_dynamic_queries` option if you prefer:
+
+```ruby
+query = ShopifyAPI::GraphQL.client.parse <<-'GRAPHQL'
+  {
+    shop {
+      name
+    }
+  }
+GRAPHQL
+
+result = ShopifyAPI::GraphQL.client.query(query)
+result.data.shop.name
+```
+
+See the [graphql-client documentation](https://github.com/github/graphql-client#defining-queries)
+for more details on defining and executing queries.
+
+## Rails integration
+`ShopifyAPI::GraphQL` integrates with Rails to automatically do the following:
+
+* load the `shopify_api:graphql:dump` Rake task
+* set the `schema_location` to be in the `db` directory in your Rails root
+* initialize clients in the Rails app initializer phase
+
+## API versioning
+`ShopifyAPI::GraphQL` is version aware and lets you easily make queries to multiple
+API versions through version specific clients if need be.
+
+If you have multiple clients and need to be explicit you can specify the version parameter:
+
+```ruby
+ShopifyAPI::GraphQL.client # defaults to the client using ShopifyAPI::Base.api_version
+ShopifyAPI::GraphQL.client('unstable')
+```
+
+## Initialization process
+`ShopifyAPI::GraphQL` is a thin integration layer which initializes `GraphQL::Client`s
+from local schema files.
+
+`ShopifyAPI::GraphQL.initialize_clients` scans `ShopifyAPI::GraphQL.schema_location`
+and creates a client for each version specific schema file found.
+
+This happens automatically in a Rails application due to our [integration](#rails-integration).
+For non-Rails applications, ensure you call `ShopifyAPI::GraphQL.initialize_clients`
+during your boot process.
+
+The goal is to have all clients created at boot so there's no schema loading,
+parsing, or client instantiation done during runtime when your app serves a request.
+
+## Migration guide
+Prior to shopify_api v9.0 the GraphQL client implementation was limited and almost
+unusable due to the client making dynamic introspection queries to Shopify's API.
+This was not only very slow but also led to unbounded memory growth.
+
+There are two steps to migrate to the new client:
+1. [Dump a local schema file](#dump-the-schema)
+2. [Migrate `client` usage](#migrate-usage)
+
+### Migrate usage
+
+Previously a client was initialized with `ShopifyAPI::GraphQL.new`:
+```ruby
+client = ShopifyAPI::GraphQL.new
+
+SHOP_NAME_QUERY = client.parse <<-'GRAPHQL'
+  {
+    shop {
+      name
+    }
+  }
+GRAPHQL
+
+result = client.query(SHOP_NAME_QUERY)
+result.data.shop.name
+```
+
+Now there's no need to initialize a client so all references to
+`ShopifyAPI::GraphQL.new` should be removed and instead the client is called
+via `ShopifyAPI::GraphQL.client`:
+
+```ruby
+client = ShopifyAPI::GraphQL.client
+
+SHOP_NAME_QUERY = client.parse <<-'GRAPHQL'
+  {
+    shop {
+      name
+    }
+  }
+GRAPHQL
+
+result = client.query(SHOP_NAME_QUERY)
+result.data.shop.name
+```
+
+See [making queries](#making-queries) for more usage details.

+ 44 - 12
lib/shopify_api/graphql/task.rake

@@ -7,30 +7,62 @@ namespace :shopify_api do
     # add the Rails environment task as a prerequisite if loaded from a Rails app
     prereqs << :environment if Rake::Task.task_defined?('environment')
 
-    desc 'Writes the Shopify Admin API GraphQL schema to a local file'
+    desc 'Dumps a local JSON schema file of the Shopify Admin API'
     task dump: prereqs do
-      site_url = ENV['SITE_URL'] || ENV['site_url']
-      shop_domain = ENV['SHOP_DOMAIN'] || ENV['shop_domain']
-      api_version = ENV['API_VERSION'] || ENV['api_version']
+      usage = <<~USAGE
+
+        Usage: rake shopify_api:graphql:dump [<args>]
+
+        Dumps a local JSON schema file of the Shopify Admin API. The schema is specific to an
+        API version and authentication is required (either OAuth or private app).
+
+        Dump the schema file for the 2020-01 API version using private app authentication:
+          $ rake shopify_api:graphql:dump SHOP_URL="https://API_KEY:PASSWORD@SHOP_NAME.myshopify.com" API_VERSION=2020-01
+
+        Dump the schema file for the unstable API version using an OAuth access token:
+          $ rake shopify_api:graphql:dump SHOP_DOMAIN=SHOP_NAME.myshopify.com ACCESS_TOKEN=abc API_VERSION=unstable
+
+        See https://github.com/Shopify/shopify_api#getting-started for more
+        details on getting started with authenticated API calls.
+
+        Arguments:
+          ACCESS_TOKEN  OAuth access token (shop specific)
+          API_VERSION   API version handle [example: 2020-01]
+          SHOP_DOMAIN   Shop domain (without path) [example: SHOP_NAME.myshopify.com]
+          SHOP_URL      Shop URL for private apps [example: https://API_KEY:PASSWORD@SHOP_NAME.myshopify.com]
+      USAGE
+
       access_token = ENV['ACCESS_TOKEN'] || ENV['access_token']
+      api_version = ENV['API_VERSION'] || ENV['api_version']
+      shop_url = ENV['SHOP_URL'] || ENV['shop_url']
+      shop_domain = ENV['SHOP_DOMAIN'] || ENV['shop_domain']
+
+      unless access_token || api_version || shop_url || shop_domain
+        puts usage
+        exit(1)
+      end
 
-      unless site_url || shop_domain
-        puts 'Either SHOP_DOMAIN or SITE_URL is required for authentication'
+      unless shop_url || shop_domain
+        puts 'Error: either SHOP_DOMAIN or SHOP_URL is required for authentication'
+        puts usage
         exit(1)
       end
 
-      if site_url && shop_domain
-        puts 'SHOP_DOMAIN and SITE_URL cannot be used together. Use one or the other for authentication.'
+      if shop_url && shop_domain
+        puts 'Error: SHOP_DOMAIN and SHOP_URL cannot be used together. Use one or the other for authentication.'
+        puts usage
         exit(1)
       end
 
       if shop_domain && !access_token
-        puts 'ACCESS_TOKEN required when SHOP_DOMAIN is used'
+        puts 'Error: ACCESS_TOKEN required when SHOP_DOMAIN is used'
+        puts usage
         exit(1)
       end
 
       unless api_version
-        puts "API_VERSION required. Example `2020-01`"
+        puts 'Error: API_VERSION required. Example: 2020-01'
+        puts usage
         exit(1)
       end
 
@@ -40,8 +72,8 @@ namespace :shopify_api do
       shopify_session = ShopifyAPI::Session.new(domain: shop_domain, token: access_token, api_version: api_version)
       ShopifyAPI::Base.activate_session(shopify_session)
 
-      if site_url
-        ShopifyAPI::Base.site = site_url
+      if shop_url
+        ShopifyAPI::Base.site = shop_url
       end
 
       schema_location = ShopifyAPI::GraphQL.schema_location