Dynamic subdomain in endpoint
nicklloyd opened this issue ยท 11 comments
Hi there - first of all, thanks for your work on this gem!
I'm looking at a current requirement of being able to have a client that is responsible for calling Shopify's Graph, but in a way that the url can be passed in as a variable.
The schema remains the same as it's only for Shopify, but they use subdomains to identify the shop you are calling...
@JanStevens and I have been trading ideas, but were hoping you'd have some insight into the best/cleanest way to approach.
Cheers!
Thanks for using Artemis!
How many subdomains are you dealing with? Is it just a handful you could hard-code, or you have to programmatically switch endpoints? If former, you could define multiple GraphQL endpoints in the config/graphql.yml
:
default: &default
...
# some other config
...
schema_path: path/to/schema_for_shopify.json
development:
shop1:
<<: *default
url: https://shop1.myshopify.com/
shop2:
<<: *default
url: https://shop2.myshopify.com/
shop3:
<<: *default
url: https://shop3.myshopify.com/
test:
...
Then you should be able to use Shop1
, shop2
, and shop3
.
If latter, you would probably monkey-patch Artemis. Perhaps you could add a scope to the connection
object using a hash in the GraphQLEndpoint
class:
artemis/lib/artemis/graphql_endpoint.rb
Lines 67 to 71 in 95cd5ee
And the Client
should pick up the right connection in here:
Lines 213 to 215 in 95cd5ee
Does that helpful? Let me know if it helps solve your problem.
If it's a public Shopify "app", the amount of shops is dynamic and ~endless. (Basically any shop that installs the app)
Also, Shopify's GraphQL root type is called QueryRoot
, while Artemis looks for Query
. I guess this could be fetched from the schema, instead of hard-coded.
Another issue is that each shop has its own access token. How would I pass that into Artemis call?
I love Artemis' API and the focus on test support! But these couple of things make it impossible for me to use it. Let me know if you know any ways around these. Thanks!
@vfonic Would you expect a single GraphQL client in that case? For example, if there are surf-shop
and chocolate-shop
, would you expect to switch the endpoint by:
Shopify.with_context(shop: "surf-shop").some_graphql_query(some: 'args')
Shopify.with_context(shop: "chocolate-shop").some_graphql_query(some: 'args')
Or would you expect a dynamically defined constant for each shop?
SurfShop.some_graphql_query(some: 'args')
ChocolateShop.some_graphql_query(some: 'args')
I'm assuming the shop id comes from a database, in which case the latter might be tricky to implement.
Great question!
Shopify made it quite seamless as you can just do:
Shop.with_shopify_session do
#...
end
Another option is to "activate" session for the shop. That's what I'd actually prefer. Something along the lines of:
# Shopify is Artemis client here
Shopify.authenticate
Shopify.products(...)
Basically anything that allows me to authenticate once, kinda like how you set the locale or time zone. This is because for a single request, I'll always query stuff on a single shop. If I need to iterate over all the shops in background job, I'll call authenticate within the loop.
Thinking more about it, maybe this could be an extension gem on top of Artemis? It doesn't feel like it should be a part of the gem itself.
I'm willing to help what I can to make this happen.
Shopify.authenticate
This call implies that it would mutate a global state, which makes it difficult to make it thread-safe. A safer way would be:
surf_shop = Shopify.authenticate_with("surf-shop")
surf_shop.products(...)
Or:
Shopify.authenticate_with("surf-shop") do |surf_shop|
surf_shop.do_stuff
surf_shop.other_stuff
end
So the endpoint toggle would be scoped to the surf_shop
object. Otherwise, we need to lock execution by other threads. How does it look to you?
Also, how does Shop.with_shopify_session { ... }
know which subdomain to establish a connection to without any identifiers?
We could definitely start with a plugin, like artemis-multidomain
or even artemis-shopify
.
Ah, I wrote Shop.with_shopify_session
, while I meant shop.with_shopify_session
, as an instance variable of Shop
model (which has shopify_domain
column).
surf_shop = Shopify.authenticate_with("surf-shop")
I love this! My idea is to create a helper function that I can call wherever. Something along the lines of this:
def graphql_shop_client
# current_shop is currently authenticated shop for which
# the request is being processed
Shopify.authenticate_with(current_shop.shopify_domain)
end
I assume Shopify.authenticate_with(current_shop.shopify_domain)
won't make any API calls, but just set the correct domain.
Awesome, I think I have enough information to spike on a multi-domain client. I'll see what I can do this weekend.
Hey @yuki24! Thanks for adding this functionality!
Is there any documentation where I could read more how to use the multi-domain functionality?
Thank you!
Awesome! Thank you so much! :)
I'd love to give it a try with my Shopify app.
I have just added a little section for multi domain. It would be greatly appreciated if you could provide feedback.