Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,119 @@ shop.with_shopify_session do
end
```

## Configuration

### Case Conversion

The gem supports automatic case conversion between Ruby's snake_case conventions and GraphQL's camelCase conventions. This feature is disabled by default to maintain backward compatibility.

To enable case conversion, configure it in your initializer:

```rb
# config/initializers/shopify_graphql.rb
ShopifyGraphql.configure do |config|
config.convert_case = true
end
```

When enabled, the gem will:
- Convert snake_case variables to camelCase when sending GraphQL requests
- Convert camelCase response keys to snake_case for easier access in Ruby

<details><summary>Example: Request Variable Conversion</summary>

```rb
# With convert_case = true
class GetProduct
include ShopifyGraphql::Query

QUERY = <<~GRAPHQL
query($product_id: ID!, $include_variants: Boolean!) {
product(id: $product_id) {
title
variants(first: 10) @include(if: $include_variants) {
edges {
node {
displayName
}
}
}
}
}
GRAPHQL

def call(product_id:, include_variants: false)
# Variables are automatically converted: product_id → productId, include_variants → includeVariants
response = execute(QUERY, product_id: product_id, include_variants: include_variants)
response.data.product
end
end

# Usage
product = GetProduct.call(
product_id: "gid://shopify/Product/12345",
include_variants: true
)
```

</details>

<details><summary>Example: Response Key Conversion</summary>

```rb
# With convert_case = true
class GetProduct
include ShopifyGraphql::Query

QUERY = <<~GRAPHQL
query($id: ID!) {
product(id: $id) {
title
featuredImage {
originalSrc
altText
}
variants(first: 5) {
edges {
node {
displayName
selectedOptions {
name
value
}
}
}
}
}
}
GRAPHQL

def call(id:)
response = execute(QUERY, id: id)
response.data.product
end
end

# Usage - all keys are automatically converted to snake_case
product = GetProduct.call(id: "gid://shopify/Product/12345")

puts product.title
puts product.featured_image.original_src # originalSrc → original_src
puts product.featured_image.alt_text # altText → alt_text

product.variants.edges.each do |edge|
puts edge.node.display_name # displayName → display_name

edge.node.selected_options.each do |option|
puts "#{option.name}: #{option.value}" # Keys converted automatically
end
end
```

</details>

**Note:** Case conversion adds a small performance overhead due to key transformation. Enable it only if you prefer Ruby naming conventions over GraphQL's camelCase.

## Conventions

To better organize your Graphql code use the following conventions:
Expand Down
13 changes: 12 additions & 1 deletion lib/shopify_graphql/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def client
end

def execute(query, headers: nil, **variables)
variables = convert_variables_to_camel_case(variables) if ShopifyGraphql.configuration.convert_case

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really need to be conditional as if the variables are passed in camelCase they will stay that way.

response = client.query(query: query, variables: variables, headers: headers)
Response.new(handle_response(response))
rescue ShopifyAPI::Errors::HttpResponseError => e
Expand All @@ -48,7 +49,11 @@ def execute(query, headers: nil, **variables)

def parsed_body(response)
if response.body.is_a?(Hash)
JSON.parse(response.body.to_json, object_class: OpenStruct)
if ShopifyGraphql.configuration.convert_case
JSON.parse(response.body.deep_transform_keys(&:underscore).to_json, object_class: OpenStruct)
else
JSON.parse(response.body.to_json, object_class: OpenStruct)
end
else
response.body
end
Expand Down Expand Up @@ -169,6 +174,12 @@ def generate_user_errors_message(messages: nil, codes: nil, fields: [])
result.join(" ")
end
end

private

def convert_variables_to_camel_case(variables)
variables.deep_transform_keys { |key| key.to_s.camelize(:lower) }
end
end

class << self
Expand Down
2 changes: 2 additions & 0 deletions lib/shopify_graphql/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ class Configuration
attr_accessor :webhook_jobs_namespace
attr_accessor :webhook_enabled_environments
attr_accessor :webhooks_manager_queue_name
attr_accessor :convert_case

def initialize
@webhooks_manager_queue_name = Rails.application.config.active_job.queue_name
@webhook_enabled_environments = ['production']
@convert_case = false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convert_case as a boolean isn't super descriptive of what this configuration option is for (converting what to what?). I would suggest either keeping it as a boolean and calling it something like use_snake_case, or making it something like case_style with a default of :camel_case and opt in to :snake_case.

end

def has_webhooks?
Expand Down
Loading