Skip to content

Commit

Permalink
add attachments (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
jshawl authored Mar 20, 2024
1 parent 21b9a3c commit 9cfe8c0
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 22 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ module.exports = {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {},
rules: {
'no-console': ['error'],
'no-unused-vars': ['error', { destructuredArrayIgnorePattern: '^_' }],
},
};
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```
curl --request POST 'http://localhost:8787/api/notify' \
-d "to=api-demo@jesse.sh&subject=🎉"
-d "to=api-readme@jesse.sh&subject=hello&body=see attached&attachments[][type]=text/plain&attachments[][content]=aGVsbG8sIHdvcmxkIQ==&attachments[][filename]=hello.txt"
```

## Local Development
Expand Down
1 change: 1 addition & 0 deletions src/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const handler = async ({ env, request }) => {
response = await postApiNotify({ env, request });
}
response = response ?? notFound();
// eslint-disable-next-line no-console
console.log(`${request.method} ${pathname} ${response.status} ${userAgent}`);
return response;
};
3 changes: 2 additions & 1 deletion src/handlers.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it, expect, beforeAll, vi } from 'vitest';
import { handler } from './handlers';
import { input } from './test';

describe('handlers', () => {
beforeAll(() => {
Expand Down Expand Up @@ -33,7 +34,7 @@ describe('handlers', () => {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ to: '[email protected]', subject: 'ok' }),
body: JSON.stringify(input),
});
await handler({ request });
expect(global.fetch).toHaveBeenCalledWith(
Expand Down
5 changes: 3 additions & 2 deletions src/mail.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const payload = ({ subject, to }) => ({
const payload = ({ subject, to, body, attachments }) => ({
// https://docs.sendgrid.com/api-reference/mail-send/mail-send#body
attachments,
content: [
{
type: 'text/plain',
value: ' ',
value: body ?? ' ',
},
],
from: {
Expand Down
37 changes: 27 additions & 10 deletions src/mail.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest';
import { describe, it, expect, vi, beforeAll } from 'vitest';
import { input } from './test';
import { mail } from './mail';

const originalFetch = global.fetch;
// https://docs.sendgrid.com/api-reference/mail-send/mail-send#body
const fixture = {
attachments: input.attachments,
content: [
{
type: 'text/plain',
value: input.body,
},
],
from: {
email: '[email protected]',
},
personalizations: [
{
subject: input.subject,
to: [
{
email: input.to,
},
],
},
],
};

describe('mail', () => {
beforeAll(() => {
global.fetch = vi.fn();
});
afterAll(() => {
global.fetch = originalFetch;
vi.clearAllMocks();
});
it('makes a request to the sendgrid api', async () => {
global.fetch.mockResolvedValueOnce({ json: () => '{}' });
const to = '[email protected]';
const subject = 'hello';
await mail({ to, subject });
await mail(input);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.sendgrid.com/v3/mail/send',
{
Expand All @@ -24,7 +41,7 @@ describe('mail', () => {
'Content-Type': 'application/json',
},
method: 'POST',
body: expect.stringMatching(/hello(.*)ex@mple.com/),
body: JSON.stringify(fixture),
},
);
});
Expand Down
21 changes: 17 additions & 4 deletions src/params.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
export const parseUrlEncoded = (string) => {
const data = Object.fromEntries(new URLSearchParams(string));

// with array[][key]=value query params
for (let key in data) {
if (key.match(/\[/)) {
const [_, object, property] = key.match(/([\w]+)\[\]\[([\w]+)/);
data[object] = data[object] || [{}];
data[object][0] = { ...data[object][0], [property]: data[key] };
delete data[key];
}
}
return data;
};

/**
* Parse a payload from a json string or a urlencoded string
* @param {Request} request
Expand All @@ -13,12 +28,10 @@ export const params = async (request) => {
}

if (contentType === 'application/x-www-form-urlencoded') {
data = Object.fromEntries(
new URLSearchParams((await request.text()) ?? ''),
);
data = parseUrlEncoded(await request.text());
}
} catch (e) {
data = {};
// pass
}

data.errors = required.reduce(
Expand Down
15 changes: 12 additions & 3 deletions src/params.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { describe, it, expect } from 'vitest';
import { params } from './params';
import { params, parseUrlEncoded } from './params';
import { input, inputUrlEncoded } from './test';

describe.each(['application/json', 'application/x-www-form-urlencoded'])(
'params',
(contentType) => {
const body = {
to: '[email protected]',
subject: 'hello world',
to: input.to,
subject: input.subject,
};

const format = {
Expand Down Expand Up @@ -41,3 +42,11 @@ describe.each(['application/json', 'application/x-www-form-urlencoded'])(
});
},
);

describe('parseUrlEncoded()', () => {
it('parses a query string into an object', async () => {
expect(parseUrlEncoded(inputUrlEncoded)).toStrictEqual({
...input,
});
});
});
14 changes: 14 additions & 0 deletions src/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const input = {
attachments: [
{
content: 'aGVsbG8sIHdvcmxkIQ==',
type: 'text/plain',
filename: 'hello.txt',
},
],
body: 'this is the body',
subject: 'hello',
to: '[email protected]',
};

export const inputUrlEncoded = `to=${input.to}&subject=${input.subject}&body=${input.body}&attachments[][type]=text/plain&attachments[][content]=aGVsbG8sIHdvcmxkIQ==&attachments[][filename]=hello.txt`;

0 comments on commit 9cfe8c0

Please sign in to comment.