如何将数据层与 next.js api 路由分开?

问题描述 投票:0回答:1

我正在使用

Next.js
MongoDB
,目前我在 TypeScript 中使用 MongoDB 客户端本身。我想知道以后是否需要更改数据库,我需要自定义
api/route.ts
文件。

我们可以不直接自定义

route.ts
文件,而是注入某种只处理数据操作的依赖项,并将该数据库部分抽象到一个单独的文件中吗?

目前,我的

api/route.ts
文件如下所示,您可以看到它与特定于供应商的数据库 API 紧密耦合。

import clientPromise from '@/app/mongodb';
import { NextResponse } from 'next/server';
import * as crypto from 'crypto';
import { v4 as uuidv4 } from "uuid";

export async function POST(request: Request) {
    const ip = // get the IP
    const sha256 = crypto.createHmac("sha256", process.env.SALT!);
    const ipHash = sha256.update(ip!);
    const ipHashDigest = ipHash.digest("hex");

    const client = await clientPromise;
    const db = client.db("survey-db");
    const creatorHistory = await db.collection("creator-ip-hash").findOne({ ipHash: ipHashDigest });

    const uuid = uuidv4();

    if (creatorHistory === null) {
        await db.collection("creator-ip-hash").insertOne({ ipHash: ipHashDigest, count: 1 });
    } else {
        const prevCount = creatorHistory.count;

        if (prevCount >= 3) {
            return NextResponse.json({ "error": "API Limit is reached" }, { status: 429 });
        }

        await db.collection("creator-ip-hash").updateOne({ ipHash: ipHashDigest }, { $set: { count: prevCount + 1 } });
    }

    const survey = await request.json();
    survey.creatorIpHash = ipHashDigest;
    survey.uuid = uuid;
    await db.collection("survey-templates").insertOne(survey);

    return NextResponse.json({ "survey-id": uuid }, { status: 201 });
}

我知道

POST
不是一个类而是一个函数,但仍然有一种方法可以以某种方式注入依赖项。我正在看这个指南:https://himynameistim.com/blog/dependency-injection-with-nextjs-and-typescript但它似乎可能是旧版本,而且也没有显示如何合并这个在 API 路由中。他们展示了
inject
injectable
的用法,但这是为了课堂。

我在 next.js GitHub 社区上找到了这个讨论:https://github.com/vercel/next.js/discussions/46805

似乎我们必须使用 package.json 或

webpack
来解决,但我仍然无法找到任何关于如何在 API 路由中使用它的正确指南。他们使用
tsyringe
作为依赖注入容器。

但是,我对任何解决方案持开放态度,只需将数据访问层与 API 路由解耦即可,因此将来,如果我必须更改数据库后端,我可以有效地完成它,如果有人以前做过,请告诉我你的想法。

typescript next.js dependency-injection data-access-layer next.js13
1个回答
0
投票

如果您的问题与设置类似于express.js的数据库连接有关,我们无法在next.js中执行此操作。 我在这里解释了原因。在 Express.js 中,数据库连接通常是长期存在的,这意味着它们在应用程序启动时建立,并在应用程序的整个生命周期中保持活动状态。但在 next.js 中,由于无服务器功能的性质,我们必须实现每个请求的连接。

但是如果你想实现依赖注入,你可以尝试微软开发的tsyringe。要在 next.js 中应用此功能,您可以遵循此。万一链接将来被破坏:

// reflect metadata allows you to use decoraters
npm install --save tsyringe reflect-metadata

修改 tsconfig.json 文件以包含以下设置,这将允许在 TypeScript 中使用装饰器。

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

使用以下设置将 .bablerc 文件添加到您的项目。

{
  "presets": ["next/babel"],
  "plugins": [ 
    # those implements the decorators
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

最后将此导入添加到您的 _app.tsx 文件或

app
目录中进行布局。

 import "reflect-metadata";

我们现在准备将我之前的代码转换为更易于维护的代码。

示例代码创建一个 graphql 客户端:

从“graphql”导入{DocumentNode};

export interface graphClient {
  query(query: DocumentNode, variables?: {}): any;
}

注意,需要使用类组件注入到构造函数中

import { inject, injectable } from "tsyringe";

@injectable()
export class getLatestPosts implements iGetLatestPosts {
  graphClient: graphClient;

  constructor(@inject("graphClient") private graphClientParam: graphClient) {
    this.graphClient = graphClientParam;
  }
...
}
© www.soinside.com 2019 - 2024. All rights reserved.