65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (1投票)

2020 年 1 月 16 日

CPOL

8分钟阅读

viewsIcon

6327

了解如何使用 Sapper、Prisma 和 GraphQL Yoga 轻松创建单页应用程序

引言

同时开发 Web 应用程序的服务器端和客户端可能具有挑战性。开发人员需要理解许多底层概念,这在解决某些问题时可能会成为障碍。

然而,近年来,技术社区已经推出了许多有用的工具,它们封装了高级方法和架构解决方案。通过利用它们,您可以轻松地组织数据存储,使用现成的抽象来构建 Web 应用程序的逻辑,等等。

在我这个两篇文章系列中,我将向您展示如何使用 SapperPrismaGraphQL Yoga 轻松创建单页应用程序。

我们将使用 Prisma 和 GraphQL Yoga 开发服务器端,并使用 Sapper 开发客户端应用程序。

在第一部分中,我们将考虑技术栈并为应用程序开发配置环境。

技术栈

Svelte

Svelte 是一个框架,可以使应用程序真正具有响应性并减少其加载量。Svelte 最有益的特性之一是它不会对应用程序的虚拟模型进行额外的计算。

Sapper

Sapper 是一个允许您使用 Svelte 编写各种规模应用程序的框架。Sapper 内部启动一个服务器,该服务器以优化和对 SEO 友好的服务器端渲染方式分发 Svelte 应用程序。

在本文中,我们将不单独讨论 Svelte 与 Sapper。

Prisma

为了创建后端和处理数据,我们将使用 PrismaGraphQL 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 的环境部署过程需要更多的配置,因为它会影响更多的基础设施组件。

  1. prisma-cli

    第一步是安装 prisma-cli。这是一个命令行实用程序,允许您管理整个 Prisma 基础设施。

    使用此实用程序,您可以

    • 将数据模式部署到 prisma-server(以及相应的数据库)
    • 自动生成一个用于处理 prisma-server 的客户端,我们将在公共服务器上使用它

    请访问 链接以更详细地了解该实用程序的特性。

    ```bash
    yarn global add prisma
    ```
  2. 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
    ```
  3. 用于 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 和数据库都是空的。它们既不知道数据模式,也不知道数据本身。

  4. 数据模式

    一旦部分基础设施准备就绪,我们就可以开始使用类似于 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` 字段中。

    您可以从 文档 中了解更多关于数据模式语法的信息。

  5. 数据模式部署

    我们将使用简单的小型 `prisma-cli` 命令来部署数据模式

    ```bash
    prisma deploy
    ```

    命令成功执行后,在地址 `https://: 4466`,我们将看到 GraphQL 模式可用,并且我们可以为每个实体使用 CRUD 操作 `createQuiz`、`updateQuiz` 等。

  6. 客户端生成

    设置 Prisma 基础设施的最后一步是生成一个客户端来处理 prisma-server。

    ```bash
    prisma generate
    ```

    在 prisma 配置中,我们指定了需要 `javascript-client` 和 `graphql-schema`。

    成功完成 `generate` 命令后,我们在 `./prisma` 目录中看到生成的文件。

  7. 安全

    此时,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 日:初始版本
© . All rights reserved.