Skip to content

Commit

Permalink
support urlencoded form data (#4)
Browse files Browse the repository at this point in the history
* support urlencoded form data

* remove prettierrc
  • Loading branch information
jshawl authored Mar 19, 2024
1 parent 98f39f2 commit 118e9d5
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 49 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Node.js CI

on:
push:
branches: ['main']
branches: ["main"]
pull_request:
branches: ['main']
branches: ["main"]

jobs:
test:
Expand All @@ -18,7 +18,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache: "npm"
- run: npm ci
- run: npm test
deploy:
Expand Down
6 changes: 0 additions & 6 deletions .prettierrc

This file was deleted.

36 changes: 24 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
const validate = async (request) => {
const required = ['subject', 'to'];
const required = ["subject", "to"];
let data;
try {
data = (await request.json()) ?? {};
if (request.headers.get("content-type") === "application/json") {
data = (await request.json()) ?? {};
}

if (
request.headers.get("content-type") ===
"application/x-www-form-urlencoded"
) {
data = Object.fromEntries(
new URLSearchParams((await request.text()) ?? ""),
);
}
} catch (e) {
data = {};
}

data.errors = required.reduce((acc, el) => {
if (!data[el]) {
return [...acc, `missing required parameter '${el}'`];
}
return acc;
}, []);
data.errors = required.reduce(
(acc, el) =>
data[el] ? acc : [...acc, `missing required parameter '${el}'`],
[],
);

return data;
};

export default {
async fetch(request, env, ctx) {
const { pathname } = new URL(request.url);
if (pathname === '/api/notify') {
if (pathname === "/api/notify") {
const { subject, to, errors } = await validate(request);
const body = {
subject,
Expand All @@ -30,13 +40,15 @@ export default {
...body,
...(errors.length && { errors }),
};
return new Response(JSON.stringify(response), { status: errors.length ? 400 : 200 });
return new Response(JSON.stringify(response), {
status: errors.length ? 400 : 200,
});
}
return new Response(
JSON.stringify(
{
message: 'Not Found',
documentation_url: 'https://www.cinotify.cc/docs',
message: "Not Found",
documentation_url: "https://www.cinotify.cc/docs",
},
null,
2,
Expand Down
82 changes: 56 additions & 26 deletions test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,76 @@
import { env, createExecutionContext, waitOnExecutionContext, SELF } from 'cloudflare:test';
import { describe, it, expect } from 'vitest';
import worker from '../src';
import {
env,
createExecutionContext,
waitOnExecutionContext,
SELF,
} from "cloudflare:test";
import { describe, it, expect } from "vitest";
import worker from "../src";

const makeRequest = async (request) => {
const send = async (request) => {
const ctx = createExecutionContext();
const response = await worker.fetch(request, env, ctx);
await waitOnExecutionContext(ctx);
return response;
};

describe('API', () => {
it('errors for missing required parameters', async () => {
const request = new Request('http://example.com/api/notify', {
method: 'POST',
describe("API", () => {
it("errors for missing required parameters", async () => {
const request = new Request("http://example.com/api/notify", {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
});
const response = await makeRequest(request);
const response = await send(request);
expect(await response.json()).toEqual({
errors: ["missing required parameter 'subject'", "missing required parameter 'to'"],
errors: [
"missing required parameter 'subject'",
"missing required parameter 'to'",
],
});
expect(response.status).toEqual(400);
});
it('does not error if the required parameters are present', async () => {
const request = new Request('http://example.com/api/notify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
to: '[email protected]',
subject: 'hello world',
it("responds to application/json and application/x-www-form-urlencoded", async () => {
const jsonResponse = await send(
new Request("http://example.com/api/notify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "[email protected]",
subject: "hello world",
}),
}),
);
expect(await jsonResponse.json()).toEqual({
to: "[email protected]",
subject: "hello world",
});
const response = await makeRequest(request);
expect(await response.json()).toEqual(expect.not.objectContaining({ errors: [] }));
expect(response.status).toEqual(200);
expect(jsonResponse.status).toEqual(200);

const formResponse = await send(
new Request("http://example.com/api/notify", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: "[email protected]&subject=hello world",
}),
);
expect(await formResponse.json()).toEqual({
to: "[email protected]",
subject: "hello world",
});
expect(formResponse.status).toEqual(200);

expect.assertions(4);
});
it('404s for undefined routes', async () => {
const request = new Request('http://example.com/undefined-route');
const response = await makeRequest(request);

it("404s for undefined routes", async () => {
const request = new Request("http://example.com/undefined-route");
const response = await send(request);
expect(response.status).toEqual(404);
});
});
4 changes: 2 additions & 2 deletions vitest.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";

export default defineWorkersConfig({
test: {
poolOptions: {
workers: {
wrangler: { configPath: './wrangler.toml' },
wrangler: { configPath: "./wrangler.toml" },
},
},
},
Expand Down

0 comments on commit 118e9d5

Please sign in to comment.