Home > Enterprise >  Generics issue while using Fastify with TypeScript
Generics issue while using Fastify with TypeScript

Time:06-15

I'm trying to build a REST API using Fastify and I'm facing this TypeScript error:

Type '(request: FastifyRequest<{    Body: IGenerateQRCode;}>, reply: FastifyReply) => Promise<never>' is not assignable to type 'RouteHandlerMethod<Server, IncomingMessage, ServerResponse, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, unknown, ResolveFastifyRequestType<...>, FastifyLoggerInstance>'.
  Types of parameters 'request' and 'request' are incompatible.
    Type 'FastifyRequest<RouteGenericInterface, Server, IncomingMessage, FastifySchema, FastifyTypeProviderDefault, unknown, ResolveFastifyRequestType<...>, FastifyLoggerInstance>' is not assignable to type 'FastifyRequest<{ Body: IGenerateQRCode; }, Server, IncomingMessage, FastifySchema, FastifyTypeProviderDefault, unknown, ResolveFastifyRequestType<...>, FastifyLoggerInstance>'.
      Type 'RouteGenericInterface' is not assignable to type '{ Body: IGenerateQRCode; }'.
        Types of property 'Body' are incompatible.
          Type 'unknown' is not assignable to type 'IGenerateQRCode'.ts(2322)
route.d.ts(140, 3): The expected type comes from property 'handler' which is declared here on type 'RouteOptions<Server, IncomingMessage, ServerResponse, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, unknown, ResolveFastifyRequestType<...>, FastifyLoggerInstance>'

The error when I add in the handler for the generateQrCode route:

import { RouteOptions } from "fastify";

import pingServer from "../controllers/pingServer";
import generateQRCode from "../controllers/generateQrCode";

const ping: RouteOptions = {
  method: "GET",
  url: "/ping",
  handler: pingServer,
};

const generateQrCode: RouteOptions = {
  method: "POST",
  url: "/generate",
  handler: generateQRCode,
};

const routes = [ping];

export default routes;

The code for that route controller is:

import { FastifyRequest, FastifyReply } from "fastify";
import { encodeURL, TransactionRequestURLFields } from "@solana/pay";
import { nanoid } from "nanoid";

import QrCodes from "../models/qrCodes";
import Users from "../models/users";

import { networks, rpcUrls } from "../constants/constants";

import { IGenerateQRCode } from "../types/IGenerateQRCode";

const generateQRCode = async (
  request: FastifyRequest<{
    Body: IGenerateQRCode;
  }>,
  reply: FastifyReply
) => {
  if (!networks.includes(request.body.network)) {
    return reply.status(400).send({
      error: "Invalid network. ",
    });
  }

  const qrCodeId = nanoid();
  const user = await Users.findOne({
    apiKey: request.headers.authorization,
  });

  const transactionRequestURLFields: TransactionRequestURLFields = {
    link: new URL(
      `https://${process.env.RAILWAY_STATIC_URL}/api/v1/mint?id=${qrCodeId}`
    ),
    label: request.body.label,
    message: request.body.message,
  };

  const solanaUrl = encodeURL(transactionRequestURLFields);

  try {
    const qrCode = new QrCodes({
      qrCodeId,
      candyMachineId: request.body.candyMachineId,
      user,
      network: request.body.network || "mainnet",
      rpcUrl: request.body.rpcUrl || rpcUrls.get(request.body.network),
      label: request.body.label || "Made with <3 by CandyPay",
      icon:
        request.body.icon ||
        "https://www.downloadclipart.net/large/candy-png-free-download.png",
    });

    await qrCode.save();

    return reply.status(200).send({
      qrCodeId,
      solanaUrl,
    });
  } catch (err) {
    console.log(err);

    return reply.status(500).send({
      message: "Internal server error",
      error: err,
    });
  }
};

export default generateQRCode;

The interface which I have used in the code of that route's controller:

export interface IGenerateQRCode {
  candyMachineId: string;
  network: string;
  rpcUrl: string;
  label: string;
  icon: string;
  message: string;
}

I am pretty sure it is the issue with the generics but I am unable to solve it

CodePudding user response:

If you change the RouteOptions type to include the generics as follows, the error is gone:

import { IncomingMessage, Server, ServerResponse } from "http";
const generateQrCode: RouteOptions<Server, IncomingMessage, ServerResponse, { Body: IGenerateQRCode; }> = {
  method: "POST",
  url: "/generate",
  handler: generateQRCode,
};

This works because the type containing the body definition should be assigned to the RouteGeneric generic.

  • Related