GraphQL 初学者指南

2025-05-25

GraphQL 初学者指南

在此处输入图片描述

如今最常讨论的术语之一是 API。很多人并不确切知道 API 是什么。简单来说,API 代表应用程序编程接口 (API)。顾名思义,它是一种供开发者、用户和消费者与数据交互的接口。

你可以把 API 想象成调酒师。你向调酒师要一杯酒,他们会给你一杯。很简单。但这有什么问题呢?

自现代网络诞生以来,构建 API 并不像听起来那么难。但学习和理解 API 却并非易事。大多数使用 API 构建程序或消费数据的人员都是开发者。因此,API 应该尽可能简洁直观。设计良好的 API 不仅易于使用和学习,而且直观易用,这一点在开始设计 API 时务必牢记。

我们使用 REST 构建 API 已经很久了。随之而来的是一些问题。使用 REST 设计构建 API 时,您会遇到以下问题:

1)你会有很多端点

2)开发人员学习和理解你的 API 会变得更加困难

3)信息获取过多或不足

为了解决这些问题,Facebook 创建了 GraphQL。如今,我认为 GraphQL 是构建 API 的最佳方式。本文将告诉你为什么你应该立即开始学习它。

在本文中,您将学习 GraphQL 的工作原理。我将向您展示如何使用 GraphQL 创建一个设计精良、高效且功能强大的 API。

你可能已经听说过 GraphQL,因为很多个人和公司都在使用它。由于 GraphQL 是开源的,它的社区已经非常庞大。

现在,是时候开始在实践中学习 GraphQL 的工作原理及其所有神奇之处了。

什么是 GraphQL?

GraphQL是 Facebook 开发的一种开源查询语言。它为我们提供了一种更高效的方式,可以设计、创建和使用 API。基本上,它是 REST 的替代品。

GraphQL 有很多功能,例如:

  1. 你只需写入所需的数据,即可获得所需的准确数据。无需像 REST 那样过度获取信息。

  2. 它为我们提供了一个单一端点,对于同一个 API,不再有版本 2 或版本 3。

  3. GraphQL 是强类型的,因此你可以在执行查询之前在 GraphQL 类型系统中验证查询。这有助于我们构建更强大的 API。

本文是对 GraphQL 的基本介绍——它为何如此强大,以及为何如今如此受欢迎。如果你想了解更多信息,我推荐你访问GraphQL 网站进行查看。

入门

本文的主要目的不是学习如何搭建 GraphQL 服务器,所以暂时不会深入探讨。我们的目标是学习 GraphQL 在实践中的工作原理,因此我们将使用一个名为 ☄️ Graphpack的零配置 GraphQL 服务器。

为了开始我们的项目,我们将创建一个新文件夹,您可以随意命名。我将它命名为graphql-server

打开终端并输入:

mkdir graphql-server
Enter fullscreen mode Exit fullscreen mode

现在,你的机器上应该已经安装了npmyarn。如果你不知道它们是什么,npm它们yarn是 JavaScript 编程语言的包管理器。对于 Node.js,默认的包管理器是npm

在创建的文件夹中输入以下命令:

npm init -y
Enter fullscreen mode Exit fullscreen mode

或者如果你使用yarn

yarn init 
Enter fullscreen mode Exit fullscreen mode

npmpackage.json将为您创建一个文件,并且您安装的所有依赖项和命令都将在那里。

所以现在,我们要安装我们将要使用的唯一依赖项。

☄️ Graphpack让你可以零配置创建 GraphQL 服务器。由于我们才刚刚开始学习 GraphQL,这将对我们后续的学习有很大帮助,无需担心服务器配置。

在您的终端中,在您的根文件夹内,像这样安装它:

npm install --save-dev graphpack
Enter fullscreen mode Exit fullscreen mode

或者,如果您使用yarn,您应该这样做:

yarn add --dev graphpack
Enter fullscreen mode Exit fullscreen mode

安装Graphpack,转到package.json文件中的脚本,并将以下代码放入其中:

"scripts": {
    "dev": "graphpack",
    "build": "graphpack build"
 }
Enter fullscreen mode Exit fullscreen mode

我们将创建一个名为的文件夹src,它将成为我们整个服务器中唯一的文件夹。

创建一个名为的文件夹src,之后,在我们的文件夹内,我们将只创建三个文件。

在我们的文件夹中src创建一个名为的文件schema.graphql。在第一个文件中,输入以下代码:

type Query {    
    hello: String    
}
Enter fullscreen mode Exit fullscreen mode

这个schema.graphql文件里包含了我们完整的 GraphQL Schema。如果你不知道它是什么,我稍后会解释——不用担心。

现在,在我们的src文件夹中,创建第二个文件。调用它resolvers.js,并在第二个文件中输入以下代码:

import { users } from "./db";

const resolvers = {    
    Query: {    
        hello: () => "Hello World!"    
    }    
};

export default resolvers;
Enter fullscreen mode Exit fullscreen mode

resolvers.js文件将成为我们提供将 GraphQL 操作转换为数据的指令的方式。

最后,在src文件夹中,创建第三个文件。命名为 src db.js,并在第三个文件中写入以下代码:

export let users = [    
    { id: 1, name: "John Doe", email: "john@gmail.com", age: 22 },    
    { id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }    
];
Enter fullscreen mode Exit fullscreen mode

本教程中我们不使用真实的数据库。因此,此db.js文件将模拟一个数据库,仅供学习之用。

现在我们的src文件夹应该是这样的:

src
  |--db.js
  |--resolvers.js
  |--schema.graphql
Enter fullscreen mode Exit fullscreen mode

现在,如果您运行命令npm run dev,或者如果您使用yarnyarn dev您应该在终端中看到此输出:

现在您可以访问localhost:4000。这意味着我们已准备好开始用 GraphQL 编写我们的第一个查询、变更和订阅。

您将看到 GraphQL Playground,这是一个功能强大的 GraphQL IDE,可帮助您优化开发工作流程。如果您想了解更多关于 GraphQL Playground 的信息,请点击此处

架构

GraphQL 有一套自己的语言用于编写模式。这是一种人类可读的模式语法,称为模式定义语言 (SDL)。无论您使用什么技术,SDL 都是相同的——您可以将其与任何您想要的语言或框架一起使用。

这种模式语言非常有用,因为它可以很容易地理解你的 API 将会包含哪些类型。你只需看一下就能明白。

类型

类型是 GraphQL 最重要的特性之一。类型是自定义对象,代表 API 的外观。例如,如果您正在构建一个社交媒体应用,您的 API 应该包含诸如帖子、用户、点赞、群组等类型。

类型包含字段,这些字段返回特定类型的数据。例如,我们要创建一个 User 类型,应该包含一些 name、email 和 age 字段。类型字段可以是任何类型,并且始终返回 Int、Float、String、Boolean、ID、对象类型列表或自定义对象类型的数据。

现在要编写我们的第一个类型,转到您的schema.graphql文件并用以下内容替换已经存在的类型查询:

type User {    
    id: ID!    
    name: String!    
    email: String!    
    age: Int    
}
Enter fullscreen mode Exit fullscreen mode

每个用户都会有一个 ID,所以我们给它指定了一个 ID 类型。用户还会有姓名和邮箱,所以我们给它指定了一个 String 类型;年龄则指定了一个 Int 类型。很简单,对吧?

但是,每行末尾的 ! 怎么办呢?感叹号表示这些字段不可为空,也就是说每个字段在每次查询中都必须返回一些数据。我们的 User 类型中唯一可空的字段是 age。

在 GraphQL 中,您将处理三个主要概念:

  1. 查询——从服务器获取数据的方式。

  2. 突变——修改服务器上的数据并获取更新数据的方式(创建、更新、删除)。

  3. 订阅——您与服务器保持实时连接的方式。

我将向你解释所有这些。让我们从查询开始。

查询

简单来说,GraphQL 中的查询就是获取数据的方式。GraphQL 查询最棒的一点就是,你只会得到你想要的精确数据,不多不少。这对我们的 API 产生了巨大的积极影响——不再像 REST API 那样出现信息获取过度或不足的情况。

我们将在 GraphQL 中创建第一个类型 Query。我们所有的查询最终都会在这个类型中。因此,首先,我们先在 Query 中schema.graphql编写一个名为 Query 的新类型:

type Query {    
    users: [User!]!    
}
Enter fullscreen mode Exit fullscreen mode

它非常简单:用户查询将返回一个或多个用户的数组。它不会返回 null,因为我们添加了!,这意味着它是一个不可为空的查询。它应该总是返回一些值。

但我们也可以返回特定的用户。为此,我们将创建一个名为 user 的新查询。在我们的查询类型中,输入以下代码:

user(id: ID!): User!
Enter fullscreen mode Exit fullscreen mode

现在我们的查询类型应该是这样的:

type Query {    
    users: [User!]!    
    user(id: ID!): User!    
}
Enter fullscreen mode Exit fullscreen mode

如你所见,在 GraphQL 中,我们也可以传递参数进行查询。在本例中,为了查询特定用户,我们将传递其 ID。

但是,你可能会想:GraphQL 如何知道从哪里获取数据?这就是为什么我们需要一个resolvers.js文件。该文件告诉 GraphQL 如何以及从哪里获取数据。

首先,打开我们的resolvers.js文件,导入db.js刚才创建的文件。你的resolvers.js文件应该如下所示:

import { users } from "./db";

const resolvers = {    
    Query: {    
        hello: () => "Hello World!"    
    }    
};

export default resolvers;
Enter fullscreen mode Exit fullscreen mode

现在,我们将创建第一个查询。转到你的resolvers.js文件并替换 hello 函数。现在你的查询类型应该如下所示:

import { users } from "./db";

const resolvers = {    
    Query: {    
        user: (parent, { id }, context, info) => {    
        return users.find(user => user.id == id);    
        },    
        users: (parent, args, context, info) => {    
            return users;    
        }    
    }    
};

export default resolvers;
Enter fullscreen mode Exit fullscreen mode

现在,解释一下它是如何工作的:

每个查询解析器都有四个参数。在用户函数中,我们将传递 id 作为参数,然后返回与传入 id 匹配的特定用户。非常简单。

在 users 函数中,我们只需返回已存在的 users 数组即可。它始终会返回所有用户。

现在,我们将测试查询是否正常工作。转到localhost:4000并输入以下代码:

query {    
    users {    
        id    
        name    
        email    
        age    
    }    
}
Enter fullscreen mode Exit fullscreen mode

它应该将我们所有的用户归还给您。

或者,如果您想返回特定用户:

query {    
    user(id: 1) {    
        id    
        name    
        email    
        age    
    }    
}
Enter fullscreen mode Exit fullscreen mode

现在,我们将开始学习突变,这是 GraphQL 中最重要的功能之一。

突变

在 GraphQL 中,突变是指修改服务器上的数据并获取更新后数据的方式。你可以将其理解为 REST 的 CUD(创建、更新、删除)。

我们将在 GraphQL 中创建第一个类型突变,所有突变最终都会在这个类型中。首先,请转到我们的文档schema.graphql并编写一个名为“mutation”的新类型:

type Mutation {    
    createUser(id: ID!, name: String!, email: String!, age: Int): User!    
    updateUser(id: ID!, name: String, email: String, age: Int): User!    
    deleteUser(id: ID!): User!    
}
Enter fullscreen mode Exit fullscreen mode

如您所见,我们将进行三次突变:

createUser:我们需要传入 ID、姓名、邮箱和年龄。它会返回一个新用户给我们。

updateUser:我们应该传入一个 ID,以及新的姓名、邮箱或年龄。它应该返回一个新用户。

deleteUser:我们应该传递一个 ID。它应该返回已删除的用户。

现在,转到我们的resolvers.js文件并在查询对象下方创建一个新的突变对象,如下所示:

Mutation: {    
    createUser: (parent, { id, name, email, age }, context, info) => {    
        const newUser = { id, name, email, age };    
        users.push(newUser);    
        return newUser;    
},   
    updateUser: (parent, { id, name, email, age }, context, info) => {    
        let newUser = users.find(user => user.id == id);    
        newUser.name = name;    
        newUser.email = email;    
        newUser.age = age;

        return newUser;
    },    
    deleteUser: (parent, { id }, context, info) => {    
        const userIndex = users.findIndex(user => user.id == id);

        if (userIndex === -1) throw new Error("User not found.");

        const deletedUsers = users.splice(userIndex, 1);

        return deletedUsers[0];     
    }    
}
Enter fullscreen mode Exit fullscreen mode

现在,我们的resolvers.js文件应该如下所示:

import { users } from "./db";

const resolvers = {    
    Query: {        
        user: (parent, { id }, context, info) => {      
            return users.find(user => user.id == id);       
        },      
        users: (parent, args, context, info) => {       
            return users;       
        }       
    },    
    Mutation: {    
        createUser: (parent, { id, name, email, age }, context, info) => {    
            const newUser = { id, name, email, age };    
            users.push(newUser);    
            return newUser;    
    },   
        updateUser: (parent, { id, name, email, age }, context, info) => {    
            let newUser = users.find(user => user.id == id);    
            newUser.name = name;    
            newUser.email = email;    
            newUser.age = age;

            return newUser;
        },    
        deleteUser: (parent, { id }, context, info) => {    
            const userIndex = users.findIndex(user => user.id === id);

            if (userIndex === -1) throw new Error("User not found.");

            const deletedUsers = users.splice(userIndex, 1);

            return deletedUsers[0];         
        }    
    }    
};

export default resolvers;
Enter fullscreen mode Exit fullscreen mode

现在,我们将测试我们的突变是否正常工作。转到localhost:4000并输入以下代码:

mutation {    
    createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) {    
        id    
        name    
        email    
        age    
    }    
}
Enter fullscreen mode Exit fullscreen mode

它应该会返回一个新用户。如果你想尝试进行新的修改,我建议你亲自尝试一下!尝试删除你创建的这个用户,看看是否正常。

最后,我们将开始了解订阅,以及它们为何如此强大。

订阅

正如我之前所说,订阅是与服务器保持实时连接的方式。这意味着,每当服务器发生事件,并且该事件被调用时,服务器都会将相应的数据发送到客户端。

通过订阅,您可以让您的应用保持更新,以适应不同用户之间的最新变化。

基本订阅如下:

subscription {    
    users {    
        id    
        name    
        email    
        age    
    }    
}
Enter fullscreen mode Exit fullscreen mode

你可能会说它和查询非常相似,确实如此。但它的工作原理不同。

当服务器中更新某些内容时,服务器将运行订阅中指定的 GraphQL 查询,并将新更新的结果发送给客户端。

我们不会在这篇特定文章中讨论订阅,但如果您想了解更多有关订阅的信息,请单击此处

结论

正如你所见,GraphQL 是一项非常强大的新技术。它赋予我们构建更优质、设计更完善的 API 的真正力量。因此,我建议你现在就开始学习它。对我来说,它最终将取代 REST。

感谢您阅读本文,请在下方发表评论!

🐦在 Twitter 上关注我!
在 GitHub 上关注我!

文章来源:https://dev.to/leonardomso/a-beginners-guide-to-graphql-3kjj
PREV
如何使用 CSS、JS 和 HTML 通过 2 个步骤制作鼠标波纹点击效果🖱️⚪ 🔍 概述 第 1 步:JAVASCRIPT 第 2 步:CSS ✔️ Windup
NEXT
🌱 10 分钟内使用 MongoDB Atlas 云、Node 和 Express 完成 REST API 云设置连接到数据库 CRUD 路由 Node 研讨会