大厂都在实践的GraphQL,你了解吗?

简介: 大厂都在实践的GraphQL,你了解吗?

前言

最近,GraphQL 在构建后端 API 方面获得越来越多大公司的青睐, 如 PayPal、Facebook、Hasura、去哪儿等公司都做了大量实践。

它为客户端提供了一种灵活的方式来请求它需要的数据,提供严格类型的接口来查询数据,以及比 REST 更好的错误处理。

与 REST API 相比,GraphQL 有其自身的优势,例如

  • 只请求所需的内容,而不是所有内容。
  • 防止为获取所需数据而进行的级联调用。
  • 客户端不需要选择 REST 路径来获取不同的资源数据。
  • 它有助于减少传输的数据量。

这些只是其中的一些优势。今天本文将介绍如何在 springboot 项目中实践 GrapQL API.

创建应用

首先可以转到 https://start.spring.io 并创建一个具有以下依赖项的应用程序:

  • Spring Boot Starter GraphQL
  • Spring Boot Starter Data JPA.(仅用于存储数据)
  • H2 数据库。

定义一个 GraphQL 模型

接下来为一个简单查询 API 定义一个 GraphQL 模型。

type Person {
  id: Int!
  name: String!
  address: [Address]
  phone: String
}
type Address {
  type: AddressType!
  street: String
}
enum AddressType {
  PRIMARY
  SECONDARY
}
type Query {
  person(id: Int!): Person
}

在这里,我们有一个类型Person,该类型具有嵌套类型Address .然后,我们提供了一个简单的查询 API,用于根据 id 获取一个Person对象数据。!表示将参数定义为必需属性。

接下来,让我们使用mutation来添加编辑数据的功能。

input AddressInput {
  id: String!
  personId: Int!
  type: AddressType!
  street: String!
}
input PersonInput {
  id: String!
  name: String!
}
type Mutation {
  createPerson(person: PersonInput): Person
  createAddress(address: AddressInput): Address
}

在这里,我们将创建地址与创建人员分开。这只是为了简单起见, 也可以将人员的创建与地址相结合。为了修改数据,这里必须使用类型定义address字段 为AddressInput类型,这是因为 mutation 仅适用于输入类型。

定义模型后,让我们将其放在资源目录中的文件夹 graphql 下,文件名为 schema.graphqls 。Spring 会自动读取扩展名为 *.graphqlss 的模型文件。

接下来开始创建对应类。

定义领域类和存储库

为了简单起见,我们将直接在 GraphQL 接口中使用领域类。

@Entity
public class Person {
    @Id
    private Integer id;
    private String name;
// Getters and setters omitted
}
@Entity
public class Address {
    @Id
    private Integer id;
    private Integer personId;
    private String street;
    private AddressType type;
// Getters and setters omitted
}
public enum AddressType {
    PRIMARY,
    SECONDARY
}

最后,我们再实现两个存储库,如下所示。

public interface PersonRepository extends JpaRepository<Person, Integer> {
}
public interface AddressRepository extends JpaRepository<Address, Integer> {
    List<Address> findByPersonId(Integer personId);
}

对于地址存储库,我们定义一个额外的方法findByPersonId来获取与人员相关的地址。

完成上述工作后,让我们来实现 GraphQL API!

实现 GraphQL 查询 API

让我们定义用于查询数据的 API。

@Controller
public class GraphQLController {
    @Autowired
    private PersonRepository personRepository;
    @Autowired
    private AddressRepository addressRepository;
    @QueryMapping(value = "person")
    public Optional<Person> getPerson(@Argument(name = "id") Integer id) {
       return personRepository.findById(id);
    }
    @SchemaMapping
    public List<Address> address(Person person) {
        return addressRepository.findByPersonId(person.getId());
    }

在这里,我们定义了用于处理查询请求的 API。带有@QueryMapping注释的函数将成为查询的处理程序。

查询名称会自动映射到函数名称,或者使用 @QueryMapping接口的value参数(在本例中为person)显式定义它。

然后,我们使用指定参数名称@Argument注释来定义输入。

@SchemaMapping将成为查询嵌套字段的处理程序。映射基于函数名称本身(如上所示)或通过设置值参数(如下所示)。

@SchemaMapping(value = "address")
public List<Address> getAddress(Person person) {
    System.out.println("Fetching address");
    return addressRepository.findByPersonId(person.getId());
}

定义 GraphQL Mutation API

让我们看看如何定义修改操作。

@MutationMapping(name = "createPerson")
public Person addPerson(@Argument(name = "person") Person person) {
    return personRepository.save(person);
}
@MutationMapping(name = "createAddress")
public Address addAddress(@Argument(name = "address") Address address) {
    return addressRepository.save(address);
}

在这里,我们遵循与@QueryMapping注释相同的原则。我们使用@MutationMapping注释将修改操作名称映射到处理程序。

完成了这一步骤,我们就编写完成了所有处理程序。

启用 GraphiQL UI

为了调试 GraphQL 请求,Spring Boot GraphQL 提供了一个已经内置的 GraphiQL UI,我们可以使用它来测试我们的 API。

要启用它,我们需要设置以下属性。

spring:
  graphql:
    graphiql:
      enabled: true

有了这个,就可以访问 /graphiql 路径上的 UI .它将自动扫描资源目录中的模型,以帮助开发人员验证 GraphQL 请求。

UI 提供了不错的功能,例如自动完成和模型文档,有助于大家轻松创建请求。

现在让我们启动应用程序并查询数据。

使用 GraphIQL 查询数据

我们可以在路径 /graphiql 访问 GraphiQL 接口。

在查询数据之前,让我们先使用 mutation 操作存储一些数据。

mutation create_person {
  createPerson(person: { id: 1, name: "amrut" }) {
    id
    name
  }
}
mutation create_Address {
  createAddress(address: { id: 1, personId: 1, type: SECONDARY, street: "some street" }) {
    type
    street
  }
}

在这里,我们创建了两个修改请求,一个用于创建一个人,一个用于创建一个地址。第一个操作创建一个人,只返回 id 和 name,因为我们只对这两个属性感兴趣。同样,创建地址接口返回地址的类型和街道。


现在,让我们查询刚刚存储的数据。

query get_person {
  person(id: 1) {
    id
    name
    address {
      type
      street
    }
  }
}


我们看到了如何使用查询和修改操作使用 GraphQL 添加和查询数据。

GraphiQL 在内部对端点 /graphql 进行 POST 调用以发送查询。因此也可以使用 curl 命令执行此操作。

curl --location --request POST 'http://localhost:8080/graphql' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query get_person{ person(id : 1){ id  name }}"}'

我们可以使用属性spring.graphql.path更改此默认路径

接下来让我们看看如何处理错误。

GraphQL 错误处理

首先看看当我们遇到错误时会发生什么。

为此,我们在调用获取电话字段时,抛出一个异常。

@SchemaMapping(value = "phone")
public String getPhone(Person person) {
    throw new RuntimeException("Did not find phone data");
}

然后,让我们调用查询电话。

query get_person {
  person(id: 1) {
    id
    name
    phone
  }
}

当我们发送请求后,我们会得到以下输出。

{
  "errors": [
    {
      "message": "INTERNAL_ERROR for e7f58f69-e800-0622-1374-046bff96d0cb",
      "locations": [
        {
          "line": 29,
          "column": 7
        }
      ],
      "path": ["person", "phone"],
      "extensions": {
        "classification": "INTERNAL_ERROR"
      }
    }
  ],
  "data": {
    "person": {
      "id": 1,
      "name": "amrut",
      "phone": null
    }
  }
}

errors 数组包含来自各种程序问题的错误列表。每个错误都有一个错误消息、一个路径和一个查询中发生错误的位置,指示哪个字段导致了错误。

出现错误时,默认程序返回上述值。

我们可以通过创建自己的错误处理程序解析器来自定义返回错误的方式。

@Component
public class ErrorHandlerResolver extends DataFetcherExceptionResolverAdapter {
    @Override
    protected List<GraphQLError> resolveToMultipleErrors(Throwable ex, DataFetchingEnvironment env) {
        GraphQLError build = GraphqlErrorBuilder.newError(env)
                .message(ex.getMessage())
                .build();
        return Arrays.asList(build);
    }
}

我们新建了一个自定义错误处理程序,其中包含异常和对数据获取环境元数据的引用,我们可以使用它获取其他信息,例如发生错误的位置和路径。

有了这个处理程序,错误现在看起来像这样:

{
  "errors": [
    {
      "message": "Did not find phone data",
      "locations": [
        {
          "line": 29,
          "column": 7
        }
      ],
      "path": ["person", "phone"],
      "extensions": {
        "classification": "DataFetchingException"
      }
    }
  ],
  "data": {
    "person": {
      "id": 1,
      "name": "amrut",
      "phone": null
    }
  }
}

小结

本文介绍了如何使用 GraphQL 来查询数据、更改数据以及定义自定义错误处理程序。

对 GranphQL有兴趣的同学可以在官网https://graphql.org/ 进一步了解更深入的知识。

相关文章
|
7月前
|
SQL 前端开发 API
前端需要学GraphQL 吗?
前端需要学GraphQL 吗?
67 2
|
7月前
|
API 开发者 网络架构
从REST到GraphQL:探究GraphQL的概念与实践
RESTful API曾经是互联网应用程序的主流,但它也存在着一些限制。随着GraphQL的出现,开发者们可以更加自由地定义和查询API,提高了应用程序的灵活性和可扩展性。本文将深入探讨GraphQL的概念和实践,并介绍如何在应用程序中使用GraphQL。
41 6
|
7月前
|
前端开发 API UED
深入浅出GraphQL:理解与实践
本文将以清晰易懂的方式介绍GraphQL的概念及其实际应用。通过对比RESTful API和GraphQL的特点,阐述GraphQL在数据查询和交互方面的优势。同时,将探讨GraphQL在现代软件开发中的实际应用,并提供一些最佳实践指南。无论您是初学者还是有经验的开发者,都能从本文中获得有益的启发和指导。
|
JSON 前端开发 API
如何使用GraphQL进行前端数据交互
如何使用GraphQL进行前端数据交互
|
API
GraphQL
GraphQL
63 0
|
JavaScript Go
搭建GraphQL服务
搭建GraphQL服务
80 0
|
SQL 前端开发 JavaScript
关于graphql快速入门
关于graphql快速入门
188 0
|
前端开发 JavaScript 小程序
从GraphQL到前端数据管理的革命 - GraphQL干货笔记
你知道吗?FaceBook、GitHub,Pinterest,Twitter,Sky,纽约时报,Shopify,Yelp这些大公司已经在使用GraphQL规范的接口规范了。再不学习就落后了。
325 0
|
JSON 前端开发 NoSQL
GraphQL 从入门到实践
本文首先介绍了 GraphQL,再通过 MongoDB + graphql + graph-pack 的组合实战应用 GraphQL,详细阐述如何使用 GraphQL 来进行增删改查和数据订阅推送,并附有使用示例,边用边学印象深刻~ 如果希望将 GraphQL 应用到前后端分离的生产环境,请期待后续文章。 本文实例代码:Github 感兴趣的同学可以加文末的微信群,一起讨论吧~
GraphQL 从入门到实践
|
JSON Unix API
graphql学习(五)
今天给之前的demo增加登录验证. 现在验证流行使用JWT(JSON web tokens),我们也选择用github.com/dgrijalva/jwt-go. 还是从models开始,增加user.
1184 0
graphql学习(五)