Shopify / shopify-api-ruby

ShopifyAPI is a lightweight gem for accessing the Shopify admin REST and GraphQL web services.
MIT License
1.05k stars 468 forks source link

Webhook Registry: Ensuring that the response body is always a Hash, even if ShopifyAPI.Context.response_as_struct is true. #1313

Closed DaveEshopGuide closed 4 months ago

DaveEshopGuide commented 4 months ago

Fixes https://github.com/Shopify/shopify-api-ruby/issues/1311 ensuring that the response body is always a Hash, even if ShopifyAPI.Context.response_as_struct is true.

Description

Had to add a Utility (ShopifyAPI::Utils::OstructHashUtils) to handle the conversion since a simple .to_h and even JSON.parse(response.body.to_json) did not work as expected (nested Keys and Array handling failed).

How has this been tested?

Wrote new Specs to test the registry process with ShopifyAPI::Context.response_as_struct = true

Checklist:

DaveEshopGuide commented 4 months ago

I have signed the CLA!

DaveEshopGuide commented 4 months ago

Hi there 👋

Thank you for flagging this issue, and taking the time to dig into this!

I was thinking instead of converting the openstruct object back to a hash. (After we have converter a hash to an openstruct), instead in the cases of the webhook registry we stop this conversion from happening in the first place.

We could do this by adding a default param to the client.query that allows us to override the context.response_as_struct value for the cases of the webhook registration.

#client.rb
        sig do
          params(
            query: String,
            variables: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
            headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
            tries: Integer,
+            response_as_struct: T::Boolean,
          ).returns(HttpResponse)
        end
-        def query(query:, variables: nil, headers: nil, tries: 1)
+        def query(query:, variables: nil, headers: nil, tries: 1, response_as_struct: Context.response_as_struct)
#registry.rb
        def webhook_registration_needed?(client, registration)
-          check_response = client.query(query: registration.build_check_query)
+          check_response = client.query(query: registration.build_check_query, response_as_struct: false)

If you would like to make these changes you are welcome to! Otherwise I am happy to put up a PR myself with these changes shortly. Thanks again!

@lizkenyon Thanks for the feedback. Yes, that seems much more reasonable. I wasn't quite happy with introducing a new Util for this anyways. I'll see what I can do.

best, Dave

DaveEshopGuide commented 4 months ago

@lizkenyon Feedback applied ;)

lizkenyon commented 4 months ago

@DaveEshopGuide Thank you for this fix!

Could you add a post to the CHANGELOG.md and then this should be good to go!

Iben1993 commented 4 months ago

Good

lizkenyon commented 4 months ago

Hey @DaveEshopGuide Could you rebase/ resolve the merge conflicts for this PR?