使用 Sapper 和 Prisma 创建问答应用程序。第一部分:环境





3.00/5 (1投票)
了解如何使用 Sapper、Prisma 和 GraphQL Yoga 轻松创建单页应用程序
引言
同时开发 Web 应用程序的服务器端和客户端可能具有挑战性。开发人员需要理解许多底层概念,这在解决某些问题时可能会成为障碍。
然而,近年来,技术社区已经推出了许多有用的工具,它们封装了高级方法和架构解决方案。通过利用它们,您可以轻松地组织数据存储,使用现成的抽象来构建 Web 应用程序的逻辑,等等。
在我这个两篇文章系列中,我将向您展示如何使用 Sapper、Prisma 和 GraphQL Yoga 轻松创建单页应用程序。
我们将使用 Prisma 和 GraphQL Yoga 开发服务器端,并使用 Sapper 开发客户端应用程序。
在第一部分中,我们将考虑技术栈并为应用程序开发配置环境。
技术栈
Svelte
Svelte 是一个框架,可以使应用程序真正具有响应性并减少其加载量。Svelte 最有益的特性之一是它不会对应用程序的虚拟模型进行额外的计算。
Sapper
Sapper 是一个允许您使用 Svelte 编写各种规模应用程序的框架。Sapper 内部启动一个服务器,该服务器以优化和对 SEO 友好的服务器端渲染方式分发 Svelte 应用程序。
在本文中,我们将不单独讨论 Svelte 与 Sapper。
Prisma
为了创建后端和处理数据,我们将使用 Prisma 和 GraphQL Yoga。
Prisma 是一套用于设计和处理关系数据库的实用工具。我们将使用 Prisma Server 和 Prisma CLI。
Prisma Server 是一个独立的服务器,它向外部公开 graphql 端点/graphql playground,并将 graphql 查询连接到数据库,并在内部正确地将它们翻译成数据库查询。此外,Prisma Server 用于数据库模式管理和迁移。
GraphQL Yoga
由于 Prisma 为每个客户端提供对数据库的根访问权限,因此 yoga-server 将在应用程序的表面层使用。GraphQL-yoga 完全支持 GraphQL 规范,并提供了一个方便的 playground,我们将在其中测试我们的查询。
基础设施部署
此设置方式假定系统中已预装 `Docker` 和 `docker-compose`。
启动 Sapper
使用官方文档中的以下片段在本地部署 Sapper 应用程序
```bash
npx degit "sveltejs/sapper-template#rollup" svelte-graphql-quiz
cd svelte-graphql-quiz
npm install
npm run dev
```
此命令将在 `svelte-graphql-quiz` 目录中创建一个 Sapper 项目,安装依赖项,并在开发模式下启动服务器。
启动 Prisma
Prisma 的环境部署过程需要更多的配置,因为它会影响更多的基础设施组件。
-
prisma-cli
第一步是安装
prisma-cli
。这是一个命令行实用程序,允许您管理整个 Prisma 基础设施。使用此实用程序,您可以
- 将数据模式部署到 prisma-server(以及相应的数据库)
- 自动生成一个用于处理 prisma-server 的客户端,我们将在公共服务器上使用它
请访问 链接以更详细地了解该实用程序的特性。
```bash yarn global add prisma ```
-
Prisma 配置
接下来,我们需要为 `
prisma-cli
` 创建一个小型配置。此配置将提供数据模式文件 (`datamodel.prisma`) 的路径、prisma-server 的地址 (`endpoint
`)、需要生成的文件的描述,以及指定它们放置的位置 (`generate
`)。```yml endpoint: https://:4466 datamodel: datamodel.prisma generate: - generator: javascript-client output: ./prisma - generator: graphql-schema output: ./prisma/schema.graphql ```
-
用于 prisma-server 的 docker-compose
Prisma-server 以 docker 镜像的形式提供,我们将在描述服务器配置时使用它。此外,在 prisma-server 配置旁边,我们需要描述数据库配置,因为
prisma-server
直接连接到数据库。我们将使用 `
docker-compose
` 来描述配置。在此代码片段中,我们描述了使用 Docker 运行 Prisma 服务器和 Postgres 数据库所需的所有配置。
```yml # docker-compose.yml version: "3" services: prisma: image: prismagraphql/prisma:1.14 restart: always ports: - "4466:4466" environment: PRISMA_CONFIG: | port: 4466 databases: default: connector: postgres host: postgres port: 5432 user: prisma password: prisma migrations: true postgres: image: postgres restart: always environment: POSTGRES_USER: prisma POSTGRES_PASSWORD: prisma volumes: - postgres:/var/lib/postgresql/data volumes: postgres: ```
下一步是启动容器
```bash docker-compose up # docker-compose up -d # for launch in the background move ```
数据库初始化并启动服务器后,Prisma 服务器附带的 yoga graphql playground 也可以在地址 `https://: 4466` 访问。
但此时模式不可用,我们无法发送任何 GraphQL 查询,因为 prisma-server 和数据库都是空的。它们既不知道数据模式,也不知道数据本身。
-
数据模式
一旦部分基础设施准备就绪,我们就可以开始使用类似于 GraphQL 的语法来描述数据模式。
这样,我们就可以通过 GraphQL 服务器显式地指示可以执行 CRUD 操作的实体。数据库模式将从此模型自动配置。
```graphql # datamodel.prisma type QuizVariant { label: String! } type QuizResults { variant: QuizVariant! @relation(name: "Variant") count: Int! } type Quiz { participantCount: Int! variants: [QuizVariant!]! @relation(link: TABLE, name: "QuizVariants") results: [QuizResults!]! @relation(link: TABLE, name: "QuizResults") } ```
在此模式中,我创建了三个实体(`
Quiz
`、`QuizResults
`、`QuizVariant
`);QuizVariant
- 描述问答变体的实体。
- 包含一个 `
label
` 字段,类型为 `String!
`。
QuizResults
- 包含与特定答案选项关联的问答结果。
- `
variant
` 字段 - 对 `QuizVariant
` 实体的引用。 - `
count
` 字段,类型为 `Int!
`,包含答案选项的结果数。
测验
- 应用程序中的主要实体。
- 在 `
variants
` 字段中存储答案选项。 - 还包含每个选项的结果,位于 `
results
` 字段中。
您可以从 文档 中了解更多关于数据模式语法的信息。
-
数据模式部署
我们将使用简单的小型 `
prisma-cli
` 命令来部署数据模式```bash prisma deploy ```
命令成功执行后,在地址 `https://: 4466`,我们将看到 GraphQL 模式可用,并且我们可以为每个实体使用 CRUD 操作 `
createQuiz
`、`updateQuiz
` 等。 -
客户端生成
设置 Prisma 基础设施的最后一步是生成一个客户端来处理 prisma-server。
```bash prisma generate ```
在 prisma 配置中,我们指定了需要 `
javascript-client
` 和 `graphql-schema
`。成功完成 `
generate
` 命令后,我们在 `./prisma` 目录中看到生成的文件。 -
安全
此时,prisma 已经启动并运行。
但还有一个重要的细节不应被忽视——安全性。
如前所述,`
prisma
` 对数据库具有根访问权限,并且不提供 ACL 系统。因此,prisma-server
以及数据库在正确配置的情况下,必须放置在私有网络中。此外,建议通过令牌配置对 Prisma 的访问。您可以从 文档 中了解更多关于这方面的信息。
GraphQL Yoga
为了构建环境的最后一部分,我们必须设置一个 GraphQL Yoga 服务器。
为此,我们将执行一个小技巧:创建一个 GraphQL 服务器实例。一个重要的条件是,我们最初为 GraphQL API 和 Sapper 启动一个单一的 Web 服务器。因此,我们在 Sapper 服务器文件中描述 GraphQL Yoga 服务器。
```js
// src/server.js
import { GraphQLServer } from "graphql-yoga";
import { prisma } from "../prisma/index";
const server = new GraphQLServer({
typeDefs: "./prisma/schema.graphql",
resolvers: {},
context: req => ({
...req,
prisma
})
});
```
在创建服务器时,我们在 `typeDefs
` 字段中指定了 `prisma generate
` 命令为我们生成的模式。此模式在 GraphQL 公共服务器上可用。
我们还将 `prisma/index` 客户端文件导入到 resolver 的上下文中,以便 prisma-server 的客户端在每个 resolver 中都可用。
GraphQLServer + Sapper
Sapper 作为中间件提供,而 yoga 作为独立的服务器提供,具有自己的路由设置和内置的 `express
` 实例,该实例又具有自己的请求路由配置。
我们需要一个单一的 Web 服务器。因此,我们将创建自己的服务器。下面是一个带有注释的服务器代码片段
```js
// assign an empty `express` instance to the GraphQL server
server.express = express();
// create http server instance
server.createHttpServer({
endpoint: "/graphql",
playground: "/playground"
})
// use general middleware for both GraphQL endpoint/playground and Sapper
server.express.use(compression({ threshold: 0 }), sirv("static", { dev }));
// create customized query routing based on GraphQL http server settings
server.express.use("/", (req, res, next) => {
if (/^\/(playground|graphql).*/.test(req.url)) {
return;
}
// use Sapper for other queries
return sapper.middleware()(req, res, next);
});
// launch a server
server.start(PORT, () => {
console.log("server started");
});
```
内部 GraphQLServer
使用预先配置的 Express 服务器。通过将其重新分配给一个空实例,我们能够进行自己的路由,并处理 Sapper(它处理所有请求)和 GraphQL 的请求,或者打开 yoga playground。
现在,如果我们运行启动 Sapper 服务器的命令(开发模式):`yarn dev
`,那么 GraphQL Yoga 服务器将可以通过地址 `https://:3000/playground` 访问,graphql 端点将通过 `https://:3000/graphql` 访问,并且我们将在根路径 `https://:3000` 上看到 Sapper 界面。
GraphQL 服务器的 Resolver
由于 prisma-server 将无法在 Web 上访问,我们需要为 Sapper 应用程序中的 GraphQL 查询创建自己的处理程序。
让我们创建一个 `quizzes` 的处理程序,它默认返回所有问答列表。
```js
// src/resolvers/quizzes.jsx
export const Query = (_parent, _args, ctx) => {
return ctx.prisma.quizzes();
}
```
此外,让我们创建一个文件,在该文件中我们将描述 resolver 的 `Query
` 和 `Mutation
` 结构。
```js
// src/resolvers/index.js
import { Query as QuizzesQuery } from "./quizzes";
export default {
Query: {
quizzes: QuizzesQueery
},
Mutation: {}
};
```
接下来,通过添加我们的 resolver
对象来更新 GraphQL 服务器构造函数。
```js
// src/server.js
...
import resolvers from "./resolvers"
...
const server = new GraphQLServer({
...
resolvers: resolvers
...
})
```
现在我们可以尝试通过 prisma-server
从数据库中获取问答列表,而 prisma-server
是通过 GraphQL Yoga 服务器访问的。
可以在 yoga playground `https://:3000/playground` 中进行的查询示例。
```graphql
{
quizzes {
participantCount
}
}
```
我们应该收到以下对我们查询的响应
```json
{
"quizzes": []
}
```
用于 Sapper 请求的 Apollo Client
我们已经构建了处理数据的基础设施,设置了 GraphQL 服务器,并与 Sapper 一起启动了它。但是 Sapper 应用程序仍然不知道 GraphQL 服务器。
让我们来解决这个问题!
安装 apollo-client
以处理 GraphQL
服务器。
```bash
yarn add apollo-boost @apollo/react-hooks graphql svelte-apollo
```
创建一个 Apollo 客户端实例
```js
// src/client/apollo.js
import ApolliClient from 'apollo-boost';
const client = new ApolliClient({
// specify the address of the graphql yoga server
uri: 'https://:3000/graphql'
});
export default client;
```
Apollo 已准备就绪!让我们测试一下。
通过 GraphQL 从 Sapper 请求数据
现在我们已准备好从 Sapper 发送数据到 GraphQL
API。让我们尝试编写第一个简单的请求。
我们将使用 Sapper 的 `preload
` 钩子进行数据预加载,然后在 `index
` 路由的上下文中显示结果。
```html
<!-- src/routes/index.svelte -->
<script context="module">
import { gql } from "apollo-boost";
import client from "../client/apollo";
const QUIZES_QUERY = gql`
{
quizzes {
participantCount
}
}
`;
export async function preload() {
const {
data: { quizzes }
} = await client.query({ query: QUIZES_QUERY });
return {
quizzes
};
}
</script>
<script>
export let quizzes;
</script>
<h3>Quizzes in service: {quizzes.length}</h3>
```
现在,如果我们转到 https://:3000,我们将看到以下来自服务器的响应
```html
<h3>Quizzes in service: 0</h3>
```
基础设施部署已成功完成。
结论
本文展示了如何创建具有数据库、GraphQL 和响应式前端的完整 Web 应用程序。
使用 Prisma,我们为 GraphQL 服务器和数据库设计了数据模式,并将该模式迁移到了 prisma-server 和数据库。
创建了一个用于处理 Sapper 应用程序请求的公共 GraphQL 服务器,我们编写了一个通过 prisma-client 请求数据的简单处理程序。
我们在 Sapper 的 `index` 路由中向 GraphQL yoga 发出了一个请求,并展示了结果。
Prisma 是一个用于快速原型化数据和这些数据的 API 的工具。
Sapper 提供了一种零配置的方法来快速开发响应式 Web 应用程序。通过结合这两个工具,我们获得了一个强大的堆栈,可以进行快速开发。
本文与 Clever Solution Inc 和 Opporty 的前软件开发人员 Roman Senin 合作撰写。
在第二篇文章中,我们将描述我们应用程序的界面和业务逻辑。
历史
- 2020 年 1 月 16 日:初始版本