我正在使用
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 路由解耦即可,因此将来,如果我必须更改数据库后端,我可以有效地完成它,如果有人以前做过,请告诉我你的想法。
如果您的问题与设置类似于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;
}
...
}