Skip to content

Commit

Permalink
Add changeset
Browse files Browse the repository at this point in the history
  • Loading branch information
G4brym committed Sep 1, 2023
1 parent edc1f39 commit 46fb1ef
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 116 deletions.
5 changes: 5 additions & 0 deletions .changeset/big-kings-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-cloudflare": minor
---

Add OpenAPI 3.1 template project
16 changes: 10 additions & 6 deletions packages/create-cloudflare/e2e-tests/workers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ describe.skipIf(frameworkToTest)("E2E: Workers templates", () => {
expect(wranglerPath).toExist();
};

test.each(["hello-world", "common", "chatgptPlugin", "queues", "scheduled", "openapi"])(
"%s",
async (name) => {
await runCli(name);
}
);
test.each([
"hello-world",
"common",
"chatgptPlugin",
"queues",
"scheduled",
"openapi",
])("%s", async (name) => {
await runCli(name);
});
});
3 changes: 0 additions & 3 deletions packages/create-cloudflare/templates/openapi/ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ This is a Cloudflare Worker with OpenAPI 3.1 using [itty-router-openapi](https:/
This is an example project made to be used as a quick start into building OpenAPI compliant Workers that generates the
`openapi.json` schema automatically from code and validates the incoming request to the defined parameters or request body.


## Get started

1. Sign up for [Cloudflare Workers](https://workers.dev). The free tier is more than enough for most use cases.
2. Clone this project and install dependencies with `npm install`
3. Run `wrangler login` to login to your Cloudflare account in wrangler
4. Run `wrangler deploy` to publish the API to Cloudflare Workers


## Project structure

1. Your main router is defined in `src/index.ts`.
2. Each endpoint has its own file in `src/endpoints/`.
3. For more information read the [itty-router-openapi official documentation](https://cloudflare.github.io/itty-router-openapi/).


## Development

1. Run `wrangler dev` to start a local instance of the API.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import {OpenAPIRoute, OpenAPIRouteSchema} from "@cloudflare/itty-router-openapi";
import {Task} from "../types";
import {
OpenAPIRoute,
OpenAPIRouteSchema,
} from "@cloudflare/itty-router-openapi";
import { Task } from "../types";

export class TaskCreate extends OpenAPIRoute {
static schema: OpenAPIRouteSchema = {
tags: ['Tasks'],
summary: 'Create a new Task',
tags: ["Tasks"],
summary: "Create a new Task",
requestBody: Task,
responses: {
'200': {
description: 'Returns the created task',
"200": {
description: "Returns the created task",
schema: {
success: Boolean,
result: {
task: Task,
}
},
},
},
},
};

async handle(request: Request, env: any, context: any, data: Record<string, any>) {
async handle(
request: Request,
env: any,
context: any,
data: Record<string, any>
) {
// Retrieve the validated request body
const taskToCreate = data.body;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,53 @@
import {OpenAPIRoute, OpenAPIRouteSchema, Path} from "@cloudflare/itty-router-openapi";
import {Task} from "../types";

import {
OpenAPIRoute,
OpenAPIRouteSchema,
Path,
} from "@cloudflare/itty-router-openapi";
import { Task } from "../types";

export class TaskDelete extends OpenAPIRoute {
static schema: OpenAPIRouteSchema = {
tags: ['Tasks'],
summary: 'Delete a Task',
tags: ["Tasks"],
summary: "Delete a Task",
parameters: {
taskSlug: Path(String, {
description: 'Task slug',
description: "Task slug",
}),
},
responses: {
'200': {
description: 'Returns if the task was deleted successfully',
"200": {
description: "Returns if the task was deleted successfully",
schema: {
success: Boolean,
result: {
task: Task
}
task: Task,
},
},
},
},
};

async handle(request: Request, env: any, context: any, data: Record<string, any>) {
async handle(
request: Request,
env: any,
context: any,
data: Record<string, any>
) {
// Retrieve the validated slug
const {taskSlug} = data.params;
const { taskSlug } = data.params;

// Implement your own object deletion here

// Return the deleted task for confirmation
return {
result: {
task: {
name: 'Build something awesome with Cloudflare Workers',
name: "Build something awesome with Cloudflare Workers",
slug: taskSlug,
description: 'Lorem Ipsum',
description: "Lorem Ipsum",
completed: true,
due_date: '2022-12-24',
}
due_date: "2022-12-24",
},
},
success: true,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,71 @@
import {OpenAPIRoute, OpenAPIRouteSchema, Path} from "@cloudflare/itty-router-openapi";
import {Task} from "../types";
import {
OpenAPIRoute,
OpenAPIRouteSchema,
Path,
} from "@cloudflare/itty-router-openapi";
import { Task } from "../types";

export class TaskFetch extends OpenAPIRoute {
static schema: OpenAPIRouteSchema = {
tags: ['Tasks'],
summary: 'Get a single Task by slug',
tags: ["Tasks"],
summary: "Get a single Task by slug",
parameters: {
taskSlug: Path(String, {
description: 'Task slug',
description: "Task slug",
}),
},
responses: {
'200': {
description: 'Returns a single task if found',
"200": {
description: "Returns a single task if found",
schema: {
success: Boolean,
result: {
task: Task
}
task: Task,
},
},
},
'404': {
description: 'Task not found',
"404": {
description: "Task not found",
schema: {
success: Boolean,
error: String
error: String,
},
},
},
};

async handle(request: Request, env: any, context: any, data: Record<string, any>) {
async handle(
request: Request,
env: any,
context: any,
data: Record<string, any>
) {
// Retrieve the validated slug
const { taskSlug } = data.params;

// Implement your own object fetch here

const exists = true
const exists = true;

// @ts-ignore: check if the object exists
if (exists === false) {
return Response.json({
success: false,
error: "Object not found"
}, {
status: 404
})
return Response.json(
{
success: false,
error: "Object not found",
},
{
status: 404,
}
);
}

return {
success: true,
task: {
name: 'my task',
name: "my task",
slug: taskSlug,
description: 'this needs to be done',
description: "this needs to be done",
completed: false,
due_date: new Date().toISOString().slice(0, 10),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
import {Task} from "../types";
import {OpenAPIRoute, OpenAPIRouteSchema, Query} from "@cloudflare/itty-router-openapi";
import { Task } from "../types";
import {
OpenAPIRoute,
OpenAPIRouteSchema,
Query,
} from "@cloudflare/itty-router-openapi";

export class TaskList extends OpenAPIRoute {
static schema: OpenAPIRouteSchema = {
tags: ['Tasks'],
summary: 'List Tasks',
tags: ["Tasks"],
summary: "List Tasks",
parameters: {
page: Query(Number, {
description: 'Page number',
description: "Page number",
default: 0,
}),
isCompleted: Query(Boolean, {
description: 'Filter by completed flag',
description: "Filter by completed flag",
required: false,
}),
},
responses: {
'200': {
description: 'Returns a list of tasks',
"200": {
description: "Returns a list of tasks",
schema: {
success: Boolean,
result: {
tasks: [Task]
}
tasks: [Task],
},
},
},
},
};

async handle(request: Request, env: any, context: any, data: Record<string, any>) {
async handle(
request: Request,
env: any,
context: any,
data: Record<string, any>
) {
// Retrieve the validated parameters
const { page, isCompleted } = data.query;

Expand All @@ -38,18 +47,18 @@ export class TaskList extends OpenAPIRoute {
success: true,
tasks: [
{
name: 'Clean my room',
slug: 'clean-room',
name: "Clean my room",
slug: "clean-room",
description: null,
completed: false,
due_date: '2025-01-05',
due_date: "2025-01-05",
},
{
name: 'Build something awesome with Cloudflare Workers',
slug: 'cloudflare-workers',
description: 'Lorem Ipsum',
name: "Build something awesome with Cloudflare Workers",
slug: "cloudflare-workers",
description: "Lorem Ipsum",
completed: true,
due_date: '2022-12-24',
due_date: "2022-12-24",
},
],
};
Expand Down
32 changes: 18 additions & 14 deletions packages/create-cloudflare/templates/openapi/ts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import { OpenAPIRouter } from "@cloudflare/itty-router-openapi";
import {TaskList} from "./endpoints/taskList";
import {TaskCreate} from "./endpoints/taskCreate";
import {TaskFetch} from "./endpoints/taskFetch";
import {TaskDelete} from "./endpoints/taskDelete";
import { TaskList } from "./endpoints/taskList";
import { TaskCreate } from "./endpoints/taskCreate";
import { TaskFetch } from "./endpoints/taskFetch";
import { TaskDelete } from "./endpoints/taskDelete";

export const router = OpenAPIRouter({
docs_url: "/"
docs_url: "/",
});

router.get('/api/tasks/', TaskList);
router.post('/api/tasks/', TaskCreate);
router.get('/api/tasks/:taskSlug/', TaskFetch);
router.delete('/api/tasks/:taskSlug/', TaskDelete);

router.get("/api/tasks/", TaskList);
router.post("/api/tasks/", TaskCreate);
router.get("/api/tasks/:taskSlug/", TaskFetch);
router.delete("/api/tasks/:taskSlug/", TaskDelete);

// 404 for everything else
router.all("*", () => Response.json({
success: false,
error: "Route not found"
}, { status: 404 }));
router.all("*", () =>
Response.json(
{
success: false,
error: "Route not found",
},
{ status: 404 }
)
);

export default {
fetch: router.handle,
Expand Down
6 changes: 3 additions & 3 deletions packages/create-cloudflare/templates/openapi/ts/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {DateTime, Str} from "@cloudflare/itty-router-openapi";
import { DateTime, Str } from "@cloudflare/itty-router-openapi";

export const Task = {
name: new Str({example: 'lorem'}),
name: new Str({ example: "lorem" }),
slug: String,
description: new Str({required: false}),
description: new Str({ required: false }),
completed: Boolean,
due_date: new DateTime(),
};
Loading

0 comments on commit 46fb1ef

Please sign in to comment.