使用GraphQL构建灵活的API

目录

引言

1. GraphQL简介

2. GraphQL基本概念

2.1 Schema

2.2 类型(Type)

2.3 根查询(Root Query)

3. 创建GraphQL服务器

3.1 安装依赖

3.2 创建服务器

3.3 运行服务器

4. 发起查询

4.1 使用GraphQL Playground

4.2 查询单个对象

4.3 查询多个对象

5. 添加Mutation

6. 使用Apollo Client

6.1 安装依赖

6.2 初始化Apollo Client

6.3 在组件中发起查询

7. Mutation与Apollo Client

8. 结论


引言

在传统的RESTful API中,客户端通常需要向服务器发起多个请求来获取所需的数据,这可能导致过度获取或不足获取数据的问题。为了解决这些问题,Facebook在2012年提出了一种新的API查询语言——GraphQL。GraphQL允许客户端精确地指定需要的数据,从而构建灵活且高效的API。本文将介绍GraphQL的基本概念和使用方法,并提供相应的代码示例。

1. GraphQL简介

GraphQL是一种由Facebook开发的API查询语言和运行时。它允许客户端精确地指定需要的数据,而不是像RESTful API那样返回固定的数据结构。通过GraphQL,客户端可以按需获取数据,避免过度获取或不足获取数据的问题,从而提高应用的性能和效率。

在GraphQL中,客户端通过发送查询(Query)来获取数据,服务器根据查询来返回相应的数据。查询的结果与查询的结构一一对应,这使得数据的获取和渲染更加灵活和高效。

2. GraphQL基本概念

在使用GraphQL构建API之前,我们需要了解一些基本概念。

2.1 Schema

在GraphQL中,Schema用于定义数据类型和查询的结构。它描述了可用的查询和数据类型,客户端根据Schema来构建查询。Schema由类型(Type)和根查询(Root Query)两部分组成。

2.2 类型(Type)

类型是GraphQL中数据的基本单位。GraphQL定义了多种内置的标量类型(如Int、String、Boolean等),也允许我们自定义复杂的类型。

type Person {
  id: ID!
  name: String!
  age: Int!
  email: String
}

上述代码定义了一个名为Person的类型,它有四个字段:idnameageemail。其中,IDString是内置的标量类型,Int是内置的标量类型,Stringemail是自定义的标量类型。

2.3 根查询(Root Query)

根查询是GraphQL的入口点。它定义了客户端可以执行的顶级查询。在根查询中,我们可以指定查询的字段和返回的数据类型。

type Query {
  person(id: ID!): Person
  allPersons: [Person!]!
}

上述代码定义了一个名为Query的根查询,它有两个字段:personallPersonsperson字段接收一个名为id的参数,并返回一个Person类型的对象。allPersons字段不接收参数,并返回一个Person类型的数组。

3. 创建GraphQL服务器

在了解了GraphQL的基本概念后,我们可以开始创建一个GraphQL服务器了。在本文中,我们将使用Node.js和Express框架来创建GraphQL服务器,并使用graphql-yoga库来简化开发。

3.1 安装依赖

在项目根目录中运行以下命令来安装graphql-yoga库和其他相关依赖:

npm install graphql-yoga

3.2 创建服务器

在项目根目录中创建一个名为server.js的文件,并在其中编写服务器的代码:

// server.js
const { GraphQLServer } = require('graphql-yoga');

// 模拟数据
const persons = [
  { id: '1', name: 'Alice', age: 28, email: '[email protected]' },
  { id: '2', name: 'Bob', age: 32, email: '[email protected]' },
  { id: '3', name: 'Charlie', age: 25, email: '[email protected]' },
];

// 定义Schema
const typeDefs = `
  type Person {
    id: ID!
    name: String!
    age: Int!
    email: String
  }

  type Query {
    person(id: ID!): Person
    allPersons: [Person!]!
  }
`;

// 定义根查询
const resolvers = {
  Query: {
    person: (_, { id }) => persons.find(person => person.id === id),
    allPersons: () => persons,
  },
};

// 创建GraphQL服务器
const server = new GraphQLServer({ typeDefs, resolvers });

// 启动服务器
server.start(() => {
  console.log('GraphQL服务器已启动');
});

在上述代码中,我们首先引入graphql-yoga库,并模拟了一些数据。然后,我们定义了Schema和根查询,根据Schema来构建查询。最后,我们创建了一个GraphQL服务器,并在指定端口启动服务器。

3.3 运行服务器

在完成上述步骤后,我们现在可以运行我们的GraphQL服务器了。在项目根目录中运行以下命令:

node server.js

这将启动GraphQL服务器,并在终端中显示“GraphQL服务器已启动”。

4. 发起查询

现在,我们已经成功创建了GraphQL服务器。接下来,我们可以通过客户端来发起查询了。

4.1 使用GraphQL Playground

graphql-yoga库提供了一个内置的GraphQL Playground,可以方便地用于发起查询和测试。在浏览器中打开http://localhost:4000,将自动进入GraphQL Playground。

4.2 查询单个对象

在GraphQL Playground中,我们可以通过输入查询语句来获取数据。尝试输入以下查询语句来获取单个对象:

query {
  person(id: "1") {
    name
    age
    email
  }
}

点击运行按钮,你将会在右侧看到查询的结果:

 
 
{
  "data": {
    "person": {
      "name": "Alice",
      "age": 28,
      "email": "[email protected]"
    }
  }
}

4.3 查询多个对象

接下来,我们可以尝试查询多个对象:

query {
  allPersons {
    name
    age
    email
  }
}

点击运行按钮,你将会在右侧看到查询的结果:

 
 
{
  "data": {
    "allPersons": [
      {
        "name": "Alice",
        "age": 28,
        "email": "[email protected]"
      },
      {
        "name": "Bob",
        "age": 32,
        "email": "[email protected]"
      },
      {
        "name": "Charlie",
        "age": 25,
        "email": "[email protected]"
      }
    ]
  }
}

5. 添加Mutation

除了查询,GraphQL还支持Mutation,用于修改数据。在GraphQL中,Mutation用于执行带有副作用的操作,比如创建、更新或删除数据。

我们可以为Person类型添加一个createPerson的Mutation来创建新的Person对象。在typeDefs中添加如下定义:

type Mutation {
  createPerson(name: String!, age: Int!, email: String): Person!
}

然后,在resolvers中添加如下定义:

 
 
const resolvers = {
  // ... 其他resolvers
  Mutation: {
    createPerson: (_, { name, age, email }) => {
      const newPerson = { id: String(persons.length + 1), name, age, email };
      persons.push(newPerson);
      return newPerson;
    },
  },
};

现在,我们可以在GraphQL Playground中尝试发起createPerson的Mutation。输入以下查询语句:

 
 
mutation {
  createPerson(name: "David", age: 30, email: "[email protected]") {
    name
    age
    email
  }
}

点击运行按钮,你将会在右侧看到查询的结果:

 
 
{
  "data": {
    "createPerson": {
      "name": "David",
      "age": 30,
      "email": "[email protected]"
    }
  }
}

再次运行查询多个对象的查询语句,你将会看到新创建的Person对象已经添加到了查询结果中。

6. 使用Apollo Client

在实际应用中,我们通常不会直接在GraphQL Playground中发起查询,而是使用JavaScript库来处理GraphQL查询。在前端开发中,一个常用的GraphQL客户端库是Apollo Client。

6.1 安装依赖

client文件夹中运行以下命令来安装Apollo Client和其他相关依赖:

npm install apollo-boost @apollo/react-hooks graphql

6.2 初始化Apollo Client

client/src/index.js文件中,我们需要初始化Apollo Client,并将其包裹在ApolloProvider中。修改代码如下:

// client/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient from 'apollo-boost';

const client = new ApolloClient({
  uri: 'http://localhost:4000',
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);

在上述代码中,我们首先引入ApolloProviderApolloClient。然后,我们创建了一个Apollo Client实例,并将其传递给ApolloProvider,这样所有的组件都可以使用Apollo Client进行GraphQL查询。

6.3 在组件中发起查询

现在,我们可以在组件中使用@apollo/react-hooks提供的useQuery钩子来发起查询。打开client/src/App.js文件,并修改代码如下:

// client/src/App.js
import React from 'react';
import { useQuery } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';

const GET_PERSONS = gql`
  query {
    allPersons {
      name
      age
      email
    }
  }
`;

function App() {
  const { loading, error, data } = useQuery(GET_PERSONS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
      <h1>前端页面</h1>
      {data.allPersons.map(person => (
        <div key={person.id}>
          <p>{person.name}</p>
          <p>{person.age}</p>
          <p>{person.email}</p>
        </div>
      ))}
    </div>
  );
}

export default App;

在上述代码中,我们首先定义了一个名为GET_PERSONS的查询。然后,我们使用useQuery钩子发起查询,并根据加载状态和错误状态来渲染不同的内容。最后,我们在页面上渲染了所有Person对象。

7. Mutation与Apollo Client

在使用Apollo Client发起Mutation时,我们需要使用useMutation钩子。打开client/src/App.js文件,并添加一个AddPerson组件来处理createPerson的Mutation:

 
 
// client/src/App.js
import React from 'react';
import { useQuery, useMutation } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';

const GET_PERSONS = gql`
  query {
    allPersons {
      name
      age
      email
    }
  }
`;

const ADD_PERSON = gql`
  mutation AddPerson($name: String!, $age: Int!, $email: String) {
    createPerson(name: $name, age: $age, email: $email) {
      name
      age
      email
    }
  }
`;

function App() {
  // useQuery 和渲染逻辑...

  const [addPerson] = useMutation(ADD_PERSON, {
    refetchQueries: [{ query: GET_PERSONS }],
  });

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      await addPerson({
        variables: { name: 'David', age: 30, email: '[email protected]' },
      });
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      {/* 其他渲染逻辑... */}
      <form onSubmit={handleSubmit}>
        <button type="submit">添加新的Person</button>
      </form>
    </div>
  );
}

export default App;

在上述代码中,我们首先定义了一个名为ADD_PERSON的Mutation。然后,我们使用useMutation钩子来发起Mutation,并在handleSubmit函数中调用addPerson方法来添加新的Person对象。

注意,我们在useMutation的选项中使用了refetchQueries,这会在Mutation执行成功后自动重新获取所有Person对象,从而更新页面上的数据。

8. 结论

通过使用GraphQL,我们成功地构建了一个灵活且高效的API。GraphQL的灵活查询语言使得客户端可以按需获取数据,避免了过度获取或不足获取数据的问题。同时,使用Apollo Client可以简化前端与后端的通信,让前端开发变得更加高效和便捷。

猜你喜欢

转载自blog.csdn.net/m0_68036862/article/details/131978532
今日推荐