Skip to content

Commit

Permalink
Add global headers to the client (#218)
Browse files Browse the repository at this point in the history
* feat: add global headers to the client

* chore: add tests for global headers

* fix: move headers logic to inside of the methods, add tests

* fix: headers type conflict

* fix: add global header to schedule and enqueue

* fix: type error

---------

Co-authored-by: CahidArda <[email protected]>
  • Loading branch information
ytkimirti and CahidArda authored Dec 10, 2024
1 parent ba392dc commit 02394bb
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 25 deletions.
118 changes: 101 additions & 17 deletions src/client/api/email.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,24 @@ import { nanoid } from "../utils";
describe("email", () => {
const qstashToken = nanoid();
const resendToken = nanoid();
const client = new Client({ baseUrl: MOCK_QSTASH_SERVER_URL, token: qstashToken });

const header = "my-header";
const headerValue = "my-header-value";
const globalHeader = "global-header";
const globalHeaderOverwritten = "global-header-overwritten";
const requestHeader = "request-header";

const globalHeaderValue = nanoid();
const overWrittenOldValue = nanoid();
const overWrittenNewValue = nanoid();
const requestHeaderValue = nanoid();

const client = new Client({
baseUrl: MOCK_QSTASH_SERVER_URL,
token: qstashToken,
headers: {
[globalHeader]: globalHeaderValue,
[globalHeaderOverwritten]: overWrittenOldValue,
},
});

test("should use resend", async () => {
await mockQStashServer({
Expand All @@ -20,15 +34,17 @@ describe("email", () => {
name: "email",
provider: resend({ token: resendToken }),
},
headers: {
[header]: headerValue,
},
body: {
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "hello world",
html: "<p>it works!</p>",
},
headers: {
"content-type": "application/json",
[globalHeaderOverwritten]: overWrittenNewValue,
[requestHeader]: requestHeaderValue,
},
});
},
responseFields: {
Expand All @@ -46,10 +62,12 @@ describe("email", () => {
html: "<p>it works!</p>",
},
headers: {
"content-type": "application/json",
authorization: `Bearer ${qstashToken}`,
"upstash-forward-authorization": `Bearer ${resendToken}`,
"content-type": "application/json",
[`upstash-forward-${header}`]: headerValue,
[`upstash-forward-${requestHeader}`]: requestHeaderValue,
[`upstash-forward-${globalHeader}`]: globalHeaderValue,
[`upstash-forward-${globalHeaderOverwritten}`]: overWrittenNewValue,
"upstash-method": "POST",
},
},
Expand All @@ -64,9 +82,6 @@ describe("email", () => {
name: "email",
provider: resend({ token: resendToken, batch: true }),
},
headers: {
[header]: headerValue,
},
body: [
{
from: "Acme <[email protected]>",
Expand All @@ -81,6 +96,11 @@ describe("email", () => {
html: "<p>it works!</p>",
},
],
headers: {
"content-type": "application/json",
[globalHeaderOverwritten]: overWrittenNewValue,
[requestHeader]: requestHeaderValue,
},
});
},
responseFields: {
Expand Down Expand Up @@ -108,9 +128,11 @@ describe("email", () => {
headers: {
authorization: `Bearer ${qstashToken}`,
"upstash-forward-authorization": `Bearer ${resendToken}`,
"content-type": "application/json",
[`upstash-forward-${header}`]: headerValue,
"upstash-method": "POST",
"content-type": "application/json",
[`upstash-forward-${requestHeader}`]: requestHeaderValue,
[`upstash-forward-${globalHeader}`]: globalHeaderValue,
[`upstash-forward-${globalHeaderOverwritten}`]: overWrittenNewValue,
},
},
});
Expand All @@ -124,9 +146,6 @@ describe("email", () => {
name: "email",
provider: resend({ token: resendToken, batch: true }),
},
headers: {
[header]: headerValue,
},
method: "PUT",
body: [
{
Expand Down Expand Up @@ -170,10 +189,75 @@ describe("email", () => {
authorization: `Bearer ${qstashToken}`,
"upstash-forward-authorization": `Bearer ${resendToken}`,
"content-type": "application/json",
[`upstash-forward-${header}`]: headerValue,
"upstash-method": "PUT",
},
},
});
});

test("should be able to enqueue", async () => {
const queueName = "resend-queue";
const queue = client.queue({ queueName });
await mockQStashServer({
execute: async () => {
await queue.enqueueJSON({
api: {
name: "email",
provider: resend({ token: resendToken, batch: true }),
},
body: [
{
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "hello world",
html: "<h1>it works!</h1>",
},
{
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "world hello",
html: "<p>it works!</p>",
},
],
headers: {
"content-type": "application/json",
[globalHeaderOverwritten]: overWrittenNewValue,
[requestHeader]: requestHeaderValue,
},
});
},
responseFields: {
body: { messageId: "msgId" },
status: 200,
},
receivesRequest: {
method: "POST",
token: qstashToken,
url: "http://localhost:8080/v2/enqueue/resend-queue/https://api.resend.com/emails/batch",
body: [
{
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "hello world",
html: "<h1>it works!</h1>",
},
{
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "world hello",
html: "<p>it works!</p>",
},
],
headers: {
authorization: `Bearer ${qstashToken}`,
"upstash-forward-authorization": `Bearer ${resendToken}`,
"content-type": "application/json",
"upstash-method": "POST",
[`upstash-forward-${requestHeader}`]: requestHeaderValue,
[`upstash-forward-${globalHeader}`]: globalHeaderValue,
[`upstash-forward-${globalHeaderOverwritten}`]: overWrittenNewValue,
},
},
});
});
});
158 changes: 158 additions & 0 deletions src/client/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { nanoid } from "nanoid";
import { Client } from "./client";
import type { PublishToUrlResponse } from "../../dist";

export const clearQueues = async (client: Client) => {
const queueDetails = await client.queue().list();
Expand Down Expand Up @@ -100,6 +101,163 @@ describe("E2E Publish", () => {
expect(verifiedMessage.maxRetries).toBeGreaterThanOrEqual(retryCount);
expect(verifiedMessage.failureCallback).toBe("https://oz.requestcatcher.com/?foo=bar");
});

test("should use global headers", async () => {
const clientWithHeaders = new Client({
token: process.env.QSTASH_TOKEN!,
// @ts-expect-error undefined header
headers: {
"undefined-header": undefined,
"test-header": "value",
"test-header-2": "value-2",
"TEST-CASE": "value-uppercase",
"test-case": "value-lowercase",
},
});
const result = await clientWithHeaders.publish({
url: "https://example.com/",
});

const verifiedMessage = await client.messages.get(result.messageId);
const messageHeaders = new Headers(verifiedMessage.header);

expect(messageHeaders.get("test-header")).toEqual("value");
expect(messageHeaders.get("test-header-2")).toEqual("value-2");
expect(messageHeaders.get("test-case")).toEqual("value-uppercase, value-lowercase");
expect(messageHeaders.get("undefined-header")).toEqual("undefined");
});

test("should override global headers", async () => {
const clientWithHeaders = new Client({
token: process.env.QSTASH_TOKEN!,
headers: {
"test-header": "value",
"test-header-2": "value-2",
"stays-same": "same",
},
});
const result = await clientWithHeaders.publish({
url: "https://example.com/",
headers: {
"Test-Header": "override-value",
},
});

const verifiedMessage = await client.messages.get(result.messageId);
const messageHeaders = new Headers(verifiedMessage.header);

expect(messageHeaders.get("test-header")).toEqual("override-value");
expect(messageHeaders.get("test-header-2")).toEqual("value-2");
expect(messageHeaders.get("stays-same")).toEqual("same");
});

test("should override global headers with publishJSON if headers are provided", async () => {
const clientWithHeaders = new Client({
token: process.env.QSTASH_TOKEN!,
headers: {
"test-header": "value",
"test-header-2": "value-2",
},
});
const result = await clientWithHeaders.publishJSON({
url: "https://example.com/",
headers: {
"Test-Header": "override-value",
"stays-same": "same",
},
});

const verifiedMessage = await client.messages.get(result.messageId);
const messageHeaders = new Headers(verifiedMessage.header);

expect(messageHeaders.get("test-header")).toEqual("override-value");
expect(messageHeaders.get("test-header-2")).toEqual("value-2");
expect(messageHeaders.get("stays-same")).toEqual("same");
});
});

describe("E2E Batch", () => {
test("should override global headers", async () => {
const client = new Client({
token: process.env.QSTASH_TOKEN!,
headers: {
"test-header": "value",
"test-header-2": "value-2",
},
});
const result = (await client.batch([
{
url: "https://example.com/1",
headers: {
"Test-Header": "override-value-1",
"stays-same": "same",
},
},
{
url: "https://example.com/2",
headers: {
"Test-Header": "override-value-2",
"stays-same": "same",
},
},
])) as PublishToUrlResponse[];

const verifiedMessage1 = await client.messages.get(result[0].messageId);
const messageHeaders1 = new Headers(verifiedMessage1.header);

const verifiedMessage2 = await client.messages.get(result[1].messageId);
const messageHeaders2 = new Headers(verifiedMessage2.header);

expect(messageHeaders1.get("test-header")).toEqual("override-value-1");
expect(messageHeaders2.get("test-header")).toEqual("override-value-2");

expect(messageHeaders1.get("stays-same")).toEqual("same");
expect(messageHeaders2.get("stays-same")).toEqual("same");

expect(messageHeaders1.get("test-header-2")).toEqual("value-2");
expect(messageHeaders2.get("test-header-2")).toEqual("value-2");
});

test("should override global headers with batchJSON", async () => {
const client = new Client({
token: process.env.QSTASH_TOKEN!,
headers: {
"test-header": "value",
"test-header-2": "value-2",
},
});
const result = (await client.batchJSON([
{
url: "https://example.com/1",
headers: {
"Test-Header": "override-value-1",
"stays-same": "same",
},
},
{
url: "https://example.com/2",
headers: {
"Test-Header": "override-value-2",
"stays-same": "same",
},
},
])) as PublishToUrlResponse[];

const verifiedMessage1 = await client.messages.get(result[0].messageId);
const messageHeaders1 = new Headers(verifiedMessage1.header);

const verifiedMessage2 = await client.messages.get(result[1].messageId);
const messageHeaders2 = new Headers(verifiedMessage2.header);

expect(messageHeaders1.get("test-header")).toEqual("override-value-1");
expect(messageHeaders2.get("test-header")).toEqual("override-value-2");

expect(messageHeaders1.get("stays-same")).toEqual("same");
expect(messageHeaders2.get("stays-same")).toEqual("same");

expect(messageHeaders1.get("test-header-2")).toEqual("value-2");
expect(messageHeaders2.get("test-header-2")).toEqual("value-2");
});
});

describe("E2E Url Group Publish", () => {
Expand Down
Loading

0 comments on commit 02394bb

Please sign in to comment.