コンテンツにスキップ

01. CRUD のコントローラ作成

バリデーションに対応する

バリデーションも実装する。Typebox はタイププロバイダー(TypeScript の型安全性を強化するもの)であり、バリデーションもしてくれる。

GitHub - fastify/fastify-type-provider-typebox: A Type Provider for Typebox

1
$ npm i @sinclair/typebox @fastify/type-provider-typebox

実装する

1
2
3
4
5
6
7
8
9
.
├── package-lock.json
├── package.json
├── src
│   ├── app.ts
│   └── todo
│       ├── todo-controller-dto.ts
│       └── todo-controller.ts
└── tsconfig.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import cors from "@fastify/cors";
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
import Fastify from "fastify";
import { todoController } from "./todo/todo-controller.js";

const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>();
await fastify.register(cors);

fastify.register(todoController, { prefix: "/todos" });

await fastify.listen({ port: 3000 });
console.log("listening");
1
2
3
4
5
export interface TodoControllerDto {
  id: string;
  name: string;
  done: boolean;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import {
  FastifyPluginAsyncTypebox,
  Type,
} from "@fastify/type-provider-typebox";
import { TodoControllerDto } from "./todo-controller-dto.js";

export const todoController: FastifyPluginAsyncTypebox = async (
  fastify,
  _options
) => {
  let todos: TodoControllerDto[] = [];

  fastify.get("/", async (request, reply) => {
    return reply.code(200).send(todos);
  });

  fastify.get(
    "/:id",
    {
      schema: {
        params: Type.Object({
          id: Type.String(),
        }),
      },
    },
    async (request, reply) => {
      const { id } = request.params;
      return reply.code(200).send(todos.find((t) => t.id === id));
    }
  );

  fastify.post(
    "/",
    {
      schema: {
        body: Type.Object({
          name: Type.String(),
          done: Type.Boolean(),
        }),
      },
    },
    async (request, reply) => {
      const { name, done } = request.body;
      console.log(name, done);
      const todo: TodoControllerDto = { id: crypto.randomUUID(), name, done };
      todos = [...todos, todo];
      return reply.code(201).send(todo);
    }
  );

  fastify.patch(
    "/:id",
    {
      schema: {
        params: Type.Object({
          id: Type.String(),
        }),
        body: Type.Object({
          name: Type.Optional(Type.String()),
          done: Type.Optional(Type.Boolean()),
        }),
      },
    },
    async (request, reply) => {
      const { id } = request.params;
      const { name, done } = request.body;
      const todo = todos.find((t) => t.id === id);
      todo!.name = name ?? todo!.name;
      todo!.done = done ?? todo!.done;
      return reply.code(200).send(todo);
    }
  );

  fastify.delete(
    "/:id",
    {
      schema: {
        params: Type.Object({
          id: Type.String(),
        }),
      },
    },
    async (request, reply) => {
      const { id } = request.params;
      todos = todos.filter((t) => t.id !== id);
      return reply.code(204).send();
    }
  );
};