• home > webfront > server > Fastify >

    Fastify JSON Schema 验证路由

    Author:zhoulujun Date:

    JSON Schema 在 Fastify 中与路由结合使用,主要是用于验证客户端请求的数据和格式化响应数据。通过定义 JSON Schema,可以确保传入

    JSON Schema 在 Fastify 中与路由结合使用,主要是用于验证客户端请求的数据和格式化响应数据。通过定义 JSON Schema,可以确保传入的请求数据满足特定格式和类型要求,同时还可以控制响应数据的结构。这样做有助于提高 API 的健壮性和安全性。

    以下是一个如何在 Fastify 路由中使用 JSON Schema 来验证请求和响应的示例:

    const fastify = require("fastify")();
    
    // 定义 JSON Schema
    const userSchema = {
      type: "object",
      required: ["username", "email", "age"],
      properties: {
        username: { type: "string" },
        email: { type: "string", format: "email" },
        age: { type: "number", minimum: 1 },
      },
    };
    
    fastify.route({
      method: "POST",
      url: "/create-user",
      schema: {
        body: userSchema, // 使用 JSON Schema 验证请求体
        response: {
          200: {
            type: "object",
            properties: {
              success: { type: "boolean" },
              id: { type: "string" },
            },
          },
        },
      },
      handler: (request, reply) => {
        // 处理请求逻辑
        // 假设创建用户成功,返回用户 ID
        reply.send({ success: true, id: "12345" });
      },
    });
    
    fastify.listen(3000, (err) => {
      if (err) throw err;
      console.log("Server is running on http://localhost:3000");
    });


    1. 定义了一个 userSchema,描述了预期的请求体格式,包括必需字段和各字段的类型。

    2. 在路由配置中,通过 schema 属性将 userSchema 应用于请求体(body),这样 Fastify 会自动验证传入的请求数据是否符合定义的 schema。

    3. 同样,也定义了响应的 schema,确保响应数据结构符合预期。

    通过这种方式,可以确保所有进入的请求都经过严格的验证,并且所有的响应都符合预定的格式,从而增强了 API 的健壮性和用户的可预测性。

    Hooks 处理登录态问题

    const fastify = require("fastify")({ logger: true });
    const secureSession = require("fastify-secure-session");
    
    // 注册 session 插件
    fastify.register(secureSession, {
      secret: "averylognsecretkey", // 应使用一个长而复杂的密钥
      cookie: {
        path: "/",
        // 配置其他 cookie 选项根据需要
      },
    });
    
    // 仅对/api/a 和/api/c 应用 preHandler 钩子
    fastify.addHook("preHandler", (request, reply, done) => {
      if (
        (request.routerPath === "/api/a" || request.routerPath === "/api/c") &&
        !request.session.user
      ) {
        request.session.redirectTo = request.raw.url;
        reply.redirect(302, "/login");
        done();
      } else {
        done();
      }
    });
    
    // 不需要 session 验证的路由
    fastify.get("/api/b", (req, reply) => {
      reply.send({ message: "Access granted for /api/b" });
    });
    
    // 需要 session 验证的路由
    fastify.get("/api/a", (req, reply) => {
      reply.send({ message: "Access granted for /api/a" });
    });
    
    fastify.get("/api/c", (req, reply) => {
      reply.send({ message: "Access granted for /api/c" });
    });
    
    // 登录页面的路由
    fastify.get("/login", (req, reply) => {
      reply.send(`Login form goes here. POST to /login to authenticate.`);
    });
    
    // 登录逻辑
    fastify.post("/login", (req, reply) => {
      const { username, password } = req.body;
      if (username === "user" && password === "password") {
        req.session.user = username;
        const redirectTo = req.session.redirectTo || "/";
        delete req.session.redirectTo;
        reply.redirect(302, redirectTo);
      } else {
        reply.code(401).send({ error: "Unauthorized" });
      }
    });
    
    // 启动服务器
    fastify.listen(3000, (err) => {
      if (err) {
        fastify.log.error(err);
        process.exit(1);
      }
      console.log(`Server listening on http://localhost:3000`);
    });


    限定参数

    下面是 post 必须传 a 和 b 参数:

    const fastify = require("fastify")();
    
    const postSchema = {
      schema: {
        body: {
          type: "object",
          required: ["a", "b"],
          properties: {
            a: { type: "string" },
            b: { type: "string" },
          },
        },
        response: {
          // 如果缺失,默认返回 400 错误,可在此处修改 400 的返回类型
          400: {
            type: "object",
            properties: {
              statusCode: { type: "number" },
              error: { type: "string" },
              message: { type: "string" },
            },
          },
        },
      },
    
      // 此处可以拦截上面的默认拦截策略
      preValidation: (request, reply, done) => {
        if (!request.body || !request.body.a || !request.body.b) {
          reply
            .code(400)
            .send({ error: "Bad Request", message: "Missing required parameters" });
          return;
        }
        done();
      },
    };
    
    fastify.post("/api/data", postSchema, (request, reply) => {
      // 如果到这里,说明 a 和 b 参数都已经通过验证
      reply.send({ message: "Success" });
    });
    
    fastify.listen(3000, (err) => {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      console.log("Server listening on port 3000");
    });

    如果不在路由中定义 preValidation 钩子和自定义的 response schema,当 POST 请求的 body 不符合定义的 JSON Schema 时,Fastify 默认会返回一个 400 错误(Bad Request)。这个错误的响应体会包含关于哪些字段不符合要求的信息,但这个信息是由 Fastify 自动生成的,可能不会像自定义错误消息那样具体或清晰。



    转载本站文章《Fastify JSON Schema 验证路由》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/server/Fastify/9303.html