Skip to content

Instantly share code, notes, and snippets.

@fabiensebban
Created April 28, 2025 09:39
Show Gist options
  • Save fabiensebban/3e3f1d0745a760b62f481e6cbd3f46f4 to your computer and use it in GitHub Desktop.
Save fabiensebban/3e3f1d0745a760b62f481e6cbd3f46f4 to your computer and use it in GitHub Desktop.
class BulkOperationMutation < ApplicationService
STAGE_UPLOAD_MUTATION = <<~'QUERY'
mutation($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
url
resourceUrl
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
QUERY
BULK_OPERATION_MUTATION = <<~'QUERY'
mutation($mutation: String!, $stagedUploadPath: String!) {
bulkOperationRunMutation(
mutation: $mutation,
stagedUploadPath: $stagedUploadPath
) {
bulkOperation {
id
url
status
}
userErrors {
field
message
}
}
}
QUERY
def initialize(mutation:, data:, session: ShopifyAPI::Context.active_session)
super()
@mutation = mutation
@session = session
@temp_file = Tempfile.new(["mutations-#{SecureRandom.uuid}", '.jsonl'])
@temp_file.write(data)
end
def call
client = ShopifyAPI::Clients::Graphql::Admin.new(session: @session)
# First, create a staged upload
staged_upload_response = client.query(
query: STAGE_UPLOAD_MUTATION,
variables: {
input: [{
filename: File.basename(@temp_file.path),
mimeType: 'text/jsonl',
httpMethod: 'POST',
resource: 'BULK_MUTATION_VARIABLES'
}]
}
)
# Then upload the file using the returned URL and parameters
target = staged_upload_response.body['data']['stagedUploadsCreate']['stagedTargets'].first
uri = URI.parse(target['url'])
form_data = target['parameters'].map { |param| [param['name'], param['value']] }
form_data << ['file', "#{@temp_file.open.read}"]
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
request = Net::HTTP::Post.new(uri)
request.set_form(form_data, 'multipart/form-data')
http.request(request)
end
staged_upload_path = target['parameters'].find { |param| param['name'] == 'key' }['value']
response = client.query(
query: BULK_OPERATION_MUTATION,
variables: {
mutation: @mutation,
stagedUploadPath: staged_upload_path,
}
).body['data']
@temp_file.unlink # Clean up the temporary file
raise BulkOperationAlreadyRunningError if response['bulkOperationRunMutation']['userErrors'].any? { |error| error['message'].include? 'A bulk mutation operation for this app and shop is already in progress' }
response.inspect
end
end
mutation = <<~QUERY
mutation XXX($arguments: ArgumentInput!){
[...]
}
QUERY
data = "" # TODO : add data formatted as JSONL string
shop = # TODO : Get Shop data
session = ShopifyAPI::Auth::Session.new(shop: shop.shopify_domain, access_token: shop.shopify_token)
BulkOperationMutation.new(mutation: mutation, data: data, session: session).call
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment