Shopify API Library for Ruby

repository·main·Indexed 22 days ago

https://github.com/shopify/shopify-api-ruby

A comprehensive suite of tools for Ruby-based Shopify apps to interact with Shopify's Admin (REST and GraphQL) and Storefront APIs. The library handles OAuth authentication, session management, and webhook processing. It includes a dedicated HttpClient for direct API calls and provides version-specific REST resources and GraphQL clients.

Tokens
26.4K
Snippets
81
Records
106
Agent score
75%

What's inside shopify-api-ruby

  1. Understand OAuth flow types in Shopify API Ruby

    main

    The library supports three primary OAuth flows depending on your app type and requirements:

    1. Token Exchange: Recommended for embedded apps. It exchanges a Shopify session token (ID token) for an access token. It is faster and prevents UI flickering because it doesn't require redirects. Access scope changes are managed via Shopify managed installation.
    2. Authorization Code Grant: Suitable for non-embedded apps. This flow requires redirecting the user to Shopify for installation and authorization. The app is responsible for managing installations and access scope changes.
    3. Client Credentials Grant: Suitable for apps without a UI. This flow does not require user interaction in a browser. Access scope changes are managed via Shopify managed installation.
  2. Implement session persistence for OAuth

    main

    Since version 12.3.0, session persistence is deprecated within the ShopifyAPI gem. The library focuses on making requests and facilitating session creation, but it does not handle storage.

    If you are not using the shopify_app gem, you must implement your own session storage method (e.g., in a database or via web framework middleware) to persist session information for subsequent authenticated API calls.

  3. Use REST Resources for API interactions

    main

    REST Resources provide a templated class library that follows an ActiveResource-like syntax, closely matching the Shopify Admin REST API schema. This is the recommended high-level way to interact with resources like Products, Orders, and Customers.

    The version of the REST resource used is determined by your ShopifyAPI::Context.setup configuration.

    # Update product title using REST Resources
    product = ShopifyAPI::Product.find(id: <product_id>)
    product.title = "My awesome product"
    product.save!
  4. Getting started with the Shopify API Ruby library

    main

    The shopify_api gem provides a comprehensive suite of tools for interacting with Shopify's APIs (REST, GraphQL, Storefront, and Webhooks) using Ruby. To begin building, you should follow the specific guides for your intended integration path:

  5. Add webhooks to the Webhook Registry

    main

    Before you can register webhooks for specific shops, you must add the desired topics to the local ShopifyAPI::Webhooks::Registry. This should be done once during app startup (e.g., when setting up ShopifyAPI::Context).

    Use ShopifyAPI::Webhooks::Registry.add_registration with the following parameters:

    • topic (String): The webhook topic (e.g., "orders/create").
    • delivery_method (Symbol): The method of delivery. Supported values: :http, :event_bridge, :pub_sub.
    • handler (Class/Module): The handler implementation (required for :http).
    • path (String): The relative path for HTTP webhooks, or an ARN/PubSub URI for other methods.
    • fields (Array of Strings or comma-separated String, optional): Filters the payload to specific fields.
    • metafieldNamespaces (Array of Strings, optional): Ensures specific metafield namespaces are included in the payload. If using fields, you must also include "metafields" in the fields list.
    • filter (String, optional): A webhooks filter string.

    Note: The local registry must be reloaded whenever your server restarts, even though the registrations are saved on the Shopify platform.

    # Basic HTTP registration
    ShopifyAPI::Webhooks::Registry.add_registration(
      topic: "orders/create",
      delivery_method: :http,
      handler: WebhookHandler,
      path: 'callback/orders/create'
    )
    
    # Registration with field filtering
    ShopifyAPI::Webhooks::Registry.add_registration(
      topic: "orders/create",
      delivery_method: :http,
      handler: WebhookHandler,
      path: 'callback/orders/create',
      fields: ["number", "note"]
    )
    
    # Registration with metafield namespaces
    ShopifyAPI::Webhooks::Registry.add_registration(
      topic: "orders/create",
      delivery_method: :http,
      handler: WebhookHandler,
      metafieldNamespaces: ["custom"]
    )
    
    # Registration with a filter
    ShopifyAPI::Webhooks::Registry.add_registration(
      topic: "products/update",
      delivery_method: :http,
      handler: WebhookHandler,
      filter: "variants.price:>=10.00"
    )
  6. Setup Shopify Context

    main

    Initialize the ShopifyAPI::Context with your application's credentials and configuration when your app starts (e.g., in application.rb for Rails). This configuration is required for the library to perform OAuth, make API requests, and handle webhooks correctly.

    ShopifyAPI::Context.setup(
      api_key: "<api-key>",
      api_secret_key: "<api-secret-key>",
      host: "<https://application-host-name.com>",
      scope: "read_orders,read_products,etc",
      is_embedded: true, # Set to true if you are building an embedded app
      api_version: "2022-01", # The version of the API you would like to use
      is_private: false, # Set to true if you have an existing private app
    )
  7. Proxy GraphQL queries for front-end clients

    main

    You can use ShopifyAPI::Utils::GraphqlProxy.proxy_query to allow your front-end to make authenticated GraphQL requests to the Shopify Admin API through your server. This utility handles authentication and proxies the request.

    Implementation Example (Rails)

    def proxy
      begin
        response = ShopifyAPI::Utils::GraphqlProxy.proxy_query(
          session: session,
          headers: request.headers.to_h,
          body: request.raw_post,
          cookies: request.cookies.to_h
        )
    
        render json: response.body, status: response.code
      rescue ShopifyAPI::Errors::InvalidGraphqlRequestError
        # Handle bad request
      rescue ShopifyAPI::Errors::SessionNotFoundError
        # Handle no session found
      end
    end

    Constraints

    • Online Sessions Only: Proxying is only supported for online sessions for non-private apps.
    • Errors:
      • Raises ShopifyAPI::Errors::SessionNotFoundError if no online tokens exist for the credentials.
      • Raises ShopifyAPI::Errors::PrivateAppError if called from a private app.
    response = ShopifyAPI::Utils::GraphqlProxy.proxy_query(
      session: session,
      headers: request.headers.to_h,
      body: request.raw_post,
      cookies: request.cookies.to_h
    )
  8. Set an active session in ShopifyAPI::Context

    main

    To avoid passing a session object to every single method call, you can set a global active_session using ShopifyAPI::Context.activate_session(session). When an API client is initialized without a specific session argument, it will automatically use the session currently set in ShopifyAPI::Context.

    #### Configuration
    def configure_app
      session = ShopifyAPI::Auth::Session.new(
          shop: "#{your_shop_name}.myshopify.com",
          access_token: "the_token_for_your_custom_app_found_in_admin"
        )
    
      ShopifyAPI::Context.setup(
        api_key: "<api-key>",
        api_secret_key: "<api-secret-key>",
        scope: "read_orders,read_products,etc",
        is_embedded: true,
        api_version: "2024-01",
        is_private: true,
      )
    
      # Activate session to be used in all subsequent API calls
      ShopifyAPI::Context.activate_session(session)
    end
    
    #### Using clients
    def make_api_request
      # This client will automatically use the active_session from Context
      graphql_client = ShopifyAPI::Clients::Graphql::Admin.new(api_version: "2024-07")
    
      query = "{ products(first: 10) { edges { node { id title } } }"
      response = graphql_client.query(query: query)
    
      # REST resources also use the active_session
      product_count = ShopifyAPI::Product.count
    end
  9. Make API calls by passing a session object to each request

    main

    You can authenticate individual API requests by passing a ShopifyAPI::Auth::Session object directly into the client constructor or the resource method. This is useful when your application manages multiple sessions simultaneously.

    # 1. Create session object
    session = ShopifyAPI::Auth::Session.new(
      shop: "#{your_shop_name}.myshopify.com",
      access_token: "the_token_for_your_custom_app_found_in_admin"
    )
    
    # 2a. Create GraphQL API client with the session
    graphql_client = ShopifyAPI::Clients::Graphql::Admin.new(session: session)
    response = graphql_client.query(query: MY_API_QUERY)
    
    # 2b. Use REST resource with the session
    product_count = ShopifyAPI::Product.count(session: session)
  10. Refactor GraphQL API calls for v10+

    main

    The graphql-client gem dependency has been removed. You must now use the new GraphQL HTTP Client classes (ShopifyAPI::Clients::Graphql::Admin or ShopifyAPI::Clients::Graphql::Storefront). Queries no longer require a local schema JSON file, and responses are accessed via hash keys rather than method chaining on a parsed object.

    # ShopifyAPI Client v10+
    client = ShopifyAPI::Clients::Graphql::Admin.new(session: session, api_version: "2023-04")
    
    SHOP_NAME_QUERY = <<~QUERY
      {
        shop {
          name
        }
      }
    QUERY
    
    response = client.query(query: query)
    shop_name = response.body["data"]["shop"]["name"]
  11. Enable expiring offline access tokens

    main

    To request expiring offline access tokens instead of non-expiring ones, set expiring_offline_access_tokens: true during ShopifyAPI::Context.setup.

    When enabled:

    • Authorization Code Grant: The OAuth flow automatically sends the expiring: 1 parameter.
    • Token Exchange: The flow requests expiring tokens.

    The resulting ShopifyAPI::Auth::Session object will include:

    • access_token: The token that will expire.
    • expires: The expiration timestamp for the access token.
    • refresh_token: A token used to obtain new access tokens.
    • refresh_token_expires: The expiration timestamp for the refresh token.
    ShopifyAPI::Context.setup(
      api_key: <SHOPIFY_API_KEY>,
      api_secret_key: <SHOPIFY_API_SECRET>,
      api_version: <SHOPIFY_API_VERSION>,
      scope: <SHOPIFY_API_SCOPES>,
      expiring_offline_access_tokens: true, # Enable expiring offline access tokens
      ...
    )
  12. Use shopify_api with Rails

    main
    If you are building a Rails application, it is highly recommended to use the shopify_app gem alongside this library. The shopify_app gem manages high-level concerns like authentication, session storage, and webhook registration, making it easier to integrate with the core shopify_api functionality.