Skip to content

Commit

Permalink
Improvement: Added more context to Shopify webhook registering errors (
Browse files Browse the repository at this point in the history
…#1090)

* Improvement: Added more context to Shopify webhook registering errors

Co-authored-by: Ahmed Ramadan <ahmedramadan1337@gmail.com>

* revert: shopify reference jobs

* fix: added error handling to some shopify client edge cases

* small changes to crud error handling

---------

Co-authored-by: Ahmed Ramadan <ahmedramadan1337@gmail.com>
Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
  • Loading branch information
3 people committed May 8, 2024
1 parent 8d34c63 commit 1fd26ff
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-pumas-whisper.md
@@ -0,0 +1,5 @@
---
"@trigger.dev/shopify": patch
---

improved error messages when a shopify webhook fails to register
24 changes: 23 additions & 1 deletion integrations/shopify/src/index.ts
Expand Up @@ -63,8 +63,30 @@ export class Shopify implements TriggerIntegration {
throw `Can't create Shopify integration (${options.id}) as apiKey was undefined`;
}

if (Object.keys(options).includes("apiSecretKey") && !options.apiSecretKey) {
throw `Can't create Shopify integration (${options.id}) as apiSecretKey was undefined`;
}

if (Object.keys(options).includes("adminAccessToken") && !options.adminAccessToken) {
throw `Can't create Shopify integration (${options.id}) as adminAccessToken was undefined`;
}

if (Object.keys(options).includes("hostName") && !options.hostName) {
throw `Can't create Shopify integration (${options.id}) as hostName was undefined`;
}

this._options = options;
this._shopDomain = this._options.hostName.replace("http://", "").replace("https://", "");
// Extract the shop domain if user has entered the full URL
this._shopDomain = this._options.hostName
.replace(/^https?:\/\//, "") // Remove http:// or https://
.replace(/\/$/, ""); // Remove trailing slash if it exists (e.g. `example.myshopify.com/`)

// Regular expression to ensure the shopDomain is a valid `.myshopify.com` domain
const shopifyDomainPattern = /^[a-zA-Z0-9-]+\.myshopify\.com$/;

if (!shopifyDomainPattern.test(this._shopDomain)) {
throw `Can't create Shopify integration (${options.id}) because hostName should be a valid ".myshopify.com" domain, not a custom primary domain. For example: my-domain.myshopify.com`;
}
}

get authSource() {
Expand Down
85 changes: 59 additions & 26 deletions integrations/shopify/src/webhooks.ts
Expand Up @@ -86,21 +86,36 @@ export function createWebhookEventSource(integration: Shopify) {
key: (params) => params.topic,
crud: {
create: async ({ io, ctx }) => {
const webhook = await io.integration.rest.Webhook.save("create-webhook", {
fromData: {
address: ctx.url,
topic: ctx.params.topic,
// fields: ctx.params.fields,
},
});

const clientSecret = await io.integration.runTask(
"get-client-secret",
async (client) => client.config.apiSecretKey
);

await io.store.job.set("set-id", "webhook-id", webhook.id);
await io.store.job.set("set-secret", "webhook-secret", clientSecret);
try {
const webhook = await io.integration.rest.Webhook.save("create-webhook", {
fromData: {
address: ctx.url,
topic: ctx.params.topic,
// fields: ctx.params.fields,
},
});

if (!webhook.id) {
throw new Error(
"Failed to create webhook. Ensure your Shopfiy client configuration is correct. Have you set the correct access scopes? Are you using the primary myshopify.com domain?"
);
}

const clientSecret = await io.integration.runTask(
"get-client-secret",
async (client) => client.config.apiSecretKey
);

await io.store.job.set("set-id", "webhook-id", webhook.id);
await io.store.job.set("set-secret", "webhook-secret", clientSecret);
} catch (error) {
if (error instanceof Error) {
await io.logger.error(`Failed to create webhook: ${error.message}`);
} else {
await io.logger.error("Failed to create webhook", { rawError: error });
}
throw error;
}
},
delete: async ({ io, ctx }) => {
const webhookId = await io.store.job.get<number>("get-webhook-id", "webhook-id");
Expand All @@ -109,23 +124,41 @@ export function createWebhookEventSource(integration: Shopify) {
throw new Error("Missing webhook ID for delete operation.");
}

await io.integration.rest.Webhook.delete("delete-webhook", {
id: webhookId,
});
try {
await io.integration.rest.Webhook.delete("delete-webhook", {
id: webhookId,
});
} catch (error) {
if (error instanceof Error) {
await io.logger.error(`Failed to delete webhook: ${error.message}`);
} else {
await io.logger.error("Failed to delete webhook", { rawError: error });
}
throw error;
}

await io.store.job.delete("delete-webhook-id", "webhook-id");
},
update: async ({ io, ctx }) => {
const webhookId = await io.store.job.get<number>("get-webhook-id", "webhook-id");

await io.integration.rest.Webhook.save("update-webhook", {
fromData: {
id: webhookId,
address: ctx.url,
topic: ctx.params.topic,
// fields: ctx.params.fields,
},
});
try {
await io.integration.rest.Webhook.save("update-webhook", {
fromData: {
id: webhookId,
address: ctx.url,
topic: ctx.params.topic,
// fields: ctx.params.fields,
},
});
} catch (error) {
if (error instanceof Error) {
await io.logger.error(`Failed to update webhook: ${error.message}`);
} else {
await io.logger.error("Failed to update webhook", { rawError: error });
}
throw error;
}
},
},
verify: async ({ request, client, ctx }) => {
Expand Down

0 comments on commit 1fd26ff

Please sign in to comment.