使用 Next.js + Prisma 2 + TypeScript + Now 实现安全且高效的全栈开发的方法

对于喜欢前端的人来说,最困难的莫过于后端实现。至少对于我来说是这样的。

所以今天我們將使用Next.js的API Routes,以一種非常簡單的方式介紹如何建立一個GraphQL的終端點API。

首先

这次使用的库如下

    • Next.js

 

    • Prisma2 w/ Photon & Lift

 

    • GraphQL Nexus

 

    • Apollo Server

 

    Apollo Client

Prisma是什么?

有兴趣的人请阅读这篇文章,它比自己解释更清楚地说明了。

简单来说,它是根据在 schema.prisma 中编写的数据库模式,在生成好的 ORM 中提供便利。

就像上面的文章已经提到的那样,由于目前仍然处于预览阶段,所以并不适合用于正式环境。只能用来玩玩而已。

GraphQL Nexus是什么?

GraphQL Nexus是Prisma公司开发的工具,它可以使code-first的GraphQL模式具有类型安全性和可扩展性。

传统的GraphQL服务器构建方法是以SDL(Schema Definition Language)为基础的。这里所说的是以.graphql结尾的文件。首先定义模式,然后在其他地方编写解析器。如果使用TypeScript,还需要编写模式的类型。结果会出现一点变更模式,就需要同时修改依赖于该模式的其他文件,当应用程序变得越来越庞大时,可扩展性就会受到影响。

采用代码优先的方式,意味着模式在代码中被定义,SDL会自动生成,这样一来,在更改模式时就省去了在其他文件中进行编辑的麻烦。稍后将会通过代码详细说明。

发展

使用create-next-app命令来创建Next.js应用程序

npx create-next-app next-prisma

用这个简单的Next.js应用程序已经创建好了。由于这次是使用TypeScript进行开发的,所以请先将pages/index.js更改为index.tsx,然后运行npm run dev试试看。Next.js会检测文件扩展名的变化,并自动创建tsconfig.json(非常方便)。然后会出现需要安装typescript、@types/react和@types/node的错误提示,请按照提示进行安装。

模块的安装

无论使用npm还是yarn都可以。由于create-next-app使用yarn来安装初始模块,因此可以使用yarn执行参考代码。

yarn add @prisma/photon apollo-server-micro graphql nexus nexus-prisma

yarn add --dev prisma2 ts-node

请在package.json文件中添加以下脚本。稍后会进行说明。

  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "generate:prisma": "prisma2 generate",
    "generate:nexus": "ts-node --project tsconfig-api.json --transpile-only api/_src/schema",
    "generate": "yarn generate:prisma && yarn generate:nexus",
    "postinstall": "yarn generate"
  }

创建prisma文件

在根目錄中創建Prisma文件。
在其中創建schema.prisma並定義以下模型。

generator photon {
  provider = "photonjs"
}

datasource db {
  provider = "postgresql"
  url      = env("PG_URL")
}

model User {
  id    Int     @id
  email String  @unique
  name  String?
}

数据源的提供者被设定为PostgreSQL,但也可以使用MySQL或MongoDB,选择您喜欢的。

在环境变量中,env会查找在.env文件中定义的环境变量,因此可以在本地和生产环境中分别使用不同的数据库。要向Now添加环境变量,需要在终端中登录Now。

now secrets add pg-url "postgresql://USERNAME:PASSWORD@localhost:PORT/postgres?SCHEMA"

# now secrets add <secret-name> <secret-value>

在Heroku等平台上可以很容易地创建PostgreSQL数据库,可以通过打开设置来进行配置。创建一个next.config.js文件,并按照以下方式定义以引用。由于Prisma2在编译期间会引用环境变量,因此也需要在构建时进行定义。

exports.default = {
  env: {
    PG_URL: '@pg-url'
  },
  build: {
    env: {
      PG_URL: '@pg-url'
    }
  }
}

在这个阶段,我们执行yarn generate:prisma命令。这将生成基于模式的代码到node_modules/@prisma/photon目录。通过这样做,将生成photon API的基础结构,我们可以使用类似photon.users.findMany({})之类的API。

顺便说一下,还有一个名为prisma2 dev的命令,当执行它时,Prisma会监视模式文件,如果有变动,则会自动重新生成photon,并且更新数据库的模式,还提供了一个名为Prisma Studio的图形界面工具。你可以直接在GUI中编辑记录,非常方便。

建立GraphQL服务器

由于Prisma作为数据层已经准备好了,我们要构建一个用于访问ORM的API层的GraphQL服务器。
想象一下,就好像有两个服务器。

以下是一种中文本地化的解释:Next.js <—-> GraphQL服务器 <—-> Prisma

首先,在根目录下创建一个名为”api”的文件夹。

普通,在Next.js中需要在/pages目录下创建api文件夹,但是在部署到now后,Photon和Next.js之间的一致性无法保持,现在无法建立连接。请在此处了解更多详细信息。然而,这样做会导致next dev无法连接到API服务器,所以请使用now dev在本地模拟now环境进行开发。希望尽快解决这个问题。

在其中创建graphql.ts、_src/schema.ts和_src/context.ts文件。

├── api
│   ├── _src
│   │   ├── context.ts
│   │   └── schema.ts
│   └── graphql.ts

大概是这样的。似乎以”_开头的文件不能作为无服务器端点处理。”

import { Photon } from '@prisma/photon';

const photon = new Photon()

export interface Context {
  photon: Photon
}
// apolloServerでphotonをcontextとして渡すと、のちにnexus側で使用可能になる
export const createContext = () => ({ photon })
import { makeSchema, objectType } from 'nexus'
import { nexusPrismaPlugin } from "nexus-prisma";
import { join } from 'path';

// __dirname使えない問題はこれで解決。詳細はこちら
// https://github.com/prisma/prisma2/issues/1021
const getPath = (fileName: string) =>
  join(process.cwd(), "generated", fileName);

// objectTypeでタイプを作る。なんでも作れるが、prisma側とあわせて作るとmodel APIを提供してくれて型を補給してくれるので、便利
const User = objectType({
  name: "User",
  definition(t) {
    t.model.email();
    t.model.id();
  }
})

const Query = objectType({
  name: "Query",
  definition(t) {
    t.crud.user();
    t.crud.users();
  }
})

const Mutation = objectType({
  name: "Mutation",
  definition(t) {
    t.crud.createOneUser({
      alias: 'createUser'
    })
  }
})

export const schema = makeSchema({
  types: [User, Query, Mutation],
  plugins: [nexusPrismaPlugin()],
  outputs: {
    typegen: getPath('nexus.ts'),
    schema: getPath('schema.graphql')
  },
  typegenAutoConfig: {
    contextType: "Context.Context",
    sources: [
      {
        source: "@prisma/photon",
        alias: "photon"
      },
      {
        source: require.resolve("./context"),
        alias: "Context"
      }
    ]
  }
})
import { ApolloServer } from 'apollo-server-micro';
import { createContext } from './_src/context';
import { schema } from './_src/schema';

const apolloServer = new ApolloServer({ schema, context: createContext() })

export const config = {
  api: {
    bodyParser: false
  }
};

export default apolloServer.createHandler({ path: '/api/graphql' });

在运行yarn generate:nexus之前,请先创建一个名为tsconfig-api.json的文件,除了基本的tsconfig.json之外。然后,在其中添加以下内容:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}

请用中文进行以下内容的改写。只需提供一种选项:
在进行Next.js开发时,如果使用”module”: “esnext”来编译Next.js代码,则无法使用ts-node进行编译。因此,只有在使用ts-node进行编译时,才会使用专门的tsconfig-api.json配置文件。在脚本中使用”–project tsconfig-api.json”进行指定。

请运行命令”yarn generate:nexus”,如果成功,将在根目录下生成一个名为”generated”的文件夹。在该文件夹中包含了nexus内部使用的”nexus.ts”文件和描述SDL的”schema.graphql”文件。这样一来,平时需要手动编写的graphql文件将会被nexus自动生成。目前阶段只有一个简单的”User”类型,但随着模型的增加和复杂度的提高,将能享受到这个自动生成的好处。

现在基本完成了,请尝试运行now dev。当访问/api/graphql的端点时,应该会打开graphql playground。然后,您可以在客户端使用apollo client,随心所欲地传递数据。

最后

prisma2目前仍处于预览阶段,开发进度可在此确认。

我觉得在一个仓库里,不需要使用单体库等,只需一个`now`命令就能部署后端和前端,这真是一个了不起的世界。

当将GitHub与Now进行链接,将能够在每个PR时进行部署,并提供一个验证用的URL,使得我们可以轻松检查差异。感觉今年对于前端工程师来说可能会是最好的一年。

强烈推荐阅读Guillermo Rauch的这篇博客文章,他作为Zeit的创始人,在这篇文章中详细阐述了未来网络开发的展望等内容。

结束了。

广告
将在 10 秒后关闭
bannerAds