簡體   English   中英

如何輸入 Fastify 回復有效載荷?

[英]How to Type Fastify Reply payloads?

我剛剛通過 Typescript 進入 Fastify 並非常享受它。

但是,我想弄清楚我是否可以輸入響應負載。 我有用於序列化工作的響應模式,這可能就足夠了,但我有內部類型的對象(例如 IUser),最好讓 Typescript 檢查。

以下工作很好,但我想返回一個 TUser,例如,如果我返回不同的東西,則有 typescript。 使用模式只會排除字段。

interface IUser {
    firstname: string,
    lastname: string
} // Not in use in example

interface IUserRequest extends RequestGenericInterface {
  Params: { username: string };
}

const getUserHandler = async (
  req: FastifyRequest<IUserRequest, RawServerBase, IncomingMessage | Http2ServerRequest>
) => {
  const { username } = req.params;
  return { ... }; // Would like to return instance of IUser
};


app.get<IUserRequest>('/:username', { schema }, helloWorldHandler);

我可以為響應擴展 RequestGenericInterface 的等價物嗎?

小更新:似乎reply.send()可用於添加類型,但為了自我文檔的緣故,提供更高的 T 會很好。

文檔中:

使用這兩個接口,定義一個新的 API 路由並將它們作為 generics 傳遞。 速記路由方法(即 .get)接受一個通用的 object RouteGenericInterface 包含五個命名屬性: BodyQuerystringParamsHeadersReply

您可以使用Reply類型。

interface MiscIPAddressRes {
  ipv4: string
}
server.get<{
  Reply: MiscIPAddressRes
}>('/misc/ip-address', async (req, res) => {
  res
    .status(_200_OKAY)
    .send({
      ipv4: req.ip // this will be typechecked
  })
})

如果您只想鍵入處理程序,則可以這樣執行

import { RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault, RouteHandler, RouteHandlerMethod } from "fastify";

const getUserHandler: RouteHandlerMethod<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    { Reply: IUser; Params: { username: string } }
> = async (
  req: FastifyRequest<IUserRequest, RawServerBase, IncomingMessage | Http2ServerRequest>
) => {
  const { username } = req.params;
  return { ... }; // Would like to return instance of IUser
};

查看類型定義后,我發現還有一種替代方法可以只對處理程序進行類型檢查(如 Julien TASSIN 的回答),如下所示:

import { FastifyReply, FastifyRequest, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
import { RouteGenericInterface } from "fastify/types/route";

interface IUser {
  firstname: string;
  lastname: string;
}

interface IUserRequest extends RouteGenericInterface {
  Params: { username: string };
  Reply: IUser; // put the response payload interface here
}

function getUserHandler(
  request: FastifyRequest<IUserRequest>,
  reply: FastifyReply<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    IUserRequest // put the request interface here
  >
) {
  const { username } = request.params;

  // do something

  // the send() parameter is now type-checked
  return reply.send({
    firstname: "James",
    lastname: "Bond",
  });
}

您還可以使用泛型創建自己的界面以節省編寫重復行,如下所示:

import { FastifyReply, FastifyRequest, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
import { RouteGenericInterface } from "fastify/types/route";

export interface FastifyReplyWithPayload<Payload extends RouteGenericInterface>
  extends FastifyReply<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    Payload
  > {}

然后使用這樣的界面:

function getUserHandler(
  request: FastifyRequest<IUserRequest>,
  reply: FastifyReplyWithPayload<IUserRequest>
) {
  const { username } = request.params;

  // do something

  // the send() parameter is also type-checked like above
  return reply.send({
    firstname: "James",
    lastname: "Bond",
  });
}

嘗試輸入這些內容真是太糟糕了。 感謝其他答案,這就是我結束的地方。 一些代碼轉儲,讓其他人的生活更輕松。

請求類型.ts

有了這個,我正在標准化我的響應以選擇性地擁有datamessage

import {
    FastifyReply,
    FastifyRequest,
    RawReplyDefaultExpression,
    RawRequestDefaultExpression,
    RawServerDefault,
} from 'fastify';

type ById = {
    id: string;
};

type ApiRequest<Body = void, Params = void, Reply = void> = {
    Body: Body;
    Params: Params;
    Reply: { data?: Reply & ById; message?: string };
};

type ApiResponse<Body = void, Params = void, Reply = {}> = FastifyReply<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    ApiRequest<Body, Params, Reply>
>;

type RouteHandlerMethod<Body = void, Params = void, Reply = void> = (
    request: FastifyRequest<ApiRequest<Body, Params, Reply>>,
    response: ApiResponse<Body, Params, Reply>
) => void;

export type DeleteRequestHandler<ReplyPayload = ById> = RouteHandlerMethod<void, ById, ReplyPayload>;
export type GetRequestHandler<ReplyPayload> = RouteHandlerMethod<void, ById, ReplyPayload>;
export type PostRequestHandler<Payload, ReplyPayload> = RouteHandlerMethod<Payload, void, ReplyPayload>;
export type PatchRequestHandler<Payload, ReplyPayload> = RouteHandlerMethod<Payload, ById, ReplyPayload>;
export type PutRequestHandler<Payload, ReplyPayload> = RouteHandlerMethod<Payload, ById, ReplyPayload>;

用法

獲取帳戶.ts - GetRequestHandler

export const getAccount: GetRequestHandler<AccountResponseDto> = async (request, reply) => {
    const { id } = request.params;
    ...
    const account = await Account.findOne.... 
    ...
    if (account) {
        return reply.status(200).send({ data: account });
    }

    return reply.status(404).send({ message: 'Account not found' });
};

刪除實體.ts - DeleteRequestHandler

export const deleteEntity: DeleteRequestHandler = async (request, reply) => {
    const { id } = request.params;
    ...
    // Indicate success by 200 and returning the id of the deleted entity
    return reply.status(200).send({ data: { id } });
};

update-account.ts - PatchRequestHandler

export const updateAccount: PatchRequestHandler<
    UpdateAccountRequestDto, 
    AccountResponseDto
> = async (request, reply) => {
    const { id } = request.params;
    ...
    return reply.status(200).send({ data: account });
};

register-account-routes.ts - 提供的處理程序沒有錯誤。

export const registerAccountRoutes = (app: FastifyInstance) => {
    app.get(EndPoints.ACCOUNT_BY_ID, getAccount);
    app.patch(EndPoints.ACCOUNT_BY_ID, updateAccount);
    app.post(EndPoints.ACCOUNTS_AUTHENTICATE, authenticate);
    app.put(EndPoints.ACCOUNTS, createAccount);
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM