GraphQL入门实践

GraphQL是一种基于api的查询语言,相对与RAST API更加的高效灵活。在REST实现中,即使你只是想获取其中的部分字段,也会响应给你完整的数据。而Graphql可以按照你的需求获取你想要的字段。

以下我们将使用Spring Boot结合GraphQL进行落地实践。

 

工程依赖

本次基于Spring Boot 2.4.4版本新建工程,引入依赖包如下:

<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.learn</groupId>
<artifactId>learn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>learn</name>
<description>Demo project for Spring Boot</description>
<properties>
    <java.version>1.8</java.version>
    <graphql.version>16.2</graphql.version>
    <guava.version>29.0-jre</guava.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.graphql-java</groupId>
        <artifactId>graphql-java</artifactId>
        <version>${graphql.version}</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>${guava.version}</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>
</dependencies>

 

编写schema配置文件

在工程resources目录下新建schema.graphqls文件。该文件中描述了查询方法、参数以及可以返回的结果字段,用户可以按需获取结果字段。

type Query {
  orderById(id: ID): Order
  commodityByName(name: String): Commodity
}

type Order {
  id: ID
  customer: String
  commodity: Commodity
}

type Commodity {
  id: ID
  name: String
  price: String
}

 

编写graphqls查询代码

我们先从新建实体类开始。新建Commodity与Order实体,并创建一些数据。代码如下:
Commodity
package com.learn.entity;

import lombok.Builder;
import lombok.Getter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Getter
@Builder
public class Commodity {
    private String id;
    private String name;
    private BigDecimal price;

    public static List<Commodity> commoditys = new ArrayList<Commodity>(){{
        add(Commodity.builder().id("commodity-1").name("从入门到放弃").price(new BigDecimal(10)).build());
        add(Commodity.builder().id("commodity-2").name("从入门到入土").price(new BigDecimal(20)).build());
    }};
}
Order:
package com.learn.entity;

import lombok.Builder;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;

@Getter
@Builder
public class Order {
    private String id;
    private String customer;
    private String commodityId;
    private Commodity commodity;

    public static List<Order> orders = new ArrayList<Order>(){{
        add(Order.builder().id("order-1").customer("张三").commodityId("commodity-2").build());
        add(Order.builder().id("order-2").customer("李四").commodityId("commodity-1").build());
    }};
}
新建GraphQLService类用于构建GraphQL对象。获取schema文件配置中的QL语句,然后后定义QL语句的解析方式。例如在buildWiring方法中Query的orderById方法是通过graphQLDataFetchers.getOrderByIdDataFetcher()来提供查询的结果数据。
package com.learn.service;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import com.learn.service.fether.GraphQLDataFetchers;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URL;

import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;

@Service
public class GraphQLService {

    private GraphQL graphQL;

    public GraphQL getGraphQL() {
        return graphQL;
    }

    @Autowired
    private GraphQLDataFetchers graphQLDataFetchers;

    @PostConstruct
    public void init() throws IOException {
        URL url = Resources.getResource("schema.graphqls");
        String sdl = Resources.toString(url, Charsets.UTF_8);
        GraphQLSchema graphQLSchema = buildSchema(sdl);
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }

    private GraphQLSchema buildSchema(String sdl) {
        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
        RuntimeWiring runtimeWiring = buildWiring();
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
    }

    private RuntimeWiring buildWiring() {
        return RuntimeWiring.newRuntimeWiring()
                .type(newTypeWiring("Query")
                        .dataFetcher("orderById", graphQLDataFetchers.getOrderByIdDataFetcher()))
                .type(newTypeWiring("Order")
                        .dataFetcher("commodity", graphQLDataFetchers.getCommodityDataFetcher()))
                .type(newTypeWiring("Query")
                        .dataFetcher("commodityByName", graphQLDataFetchers.getCommodityByNameDataFetcher()))
                .build();
    }
}
新建GraphQLDataFetchers类,用于提供查询数据dataFetchingEnvironment.getArgument获取请求中的查询参数,然后orders中找到与之匹配的order。
下面提供数据的方法的返回都是DataFetcher类型,DataFetcher在执行查询时,调用底层服务查询Order中提取出匹配的结果字段。 
package com.learn.service.fether;

import com.learn.entity.Commodity;
import com.learn.entity.Order;
import graphql.schema.DataFetcher;
import org.springframework.stereotype.Component;

@Component
public class GraphQLDataFetchers {


    public DataFetcher getOrderByIdDataFetcher() {
        return dataFetchingEnvironment -> {
            String orderId = dataFetchingEnvironment.getArgument("id");
            return Order.orders
                    .stream()
                    .filter(order -> order.getId().equals(orderId))
                    .findFirst()
                    .orElse(null);
        };
    }

    public DataFetcher getCommodityDataFetcher() {
        return dataFetchingEnvironment -> {
            Order order = dataFetchingEnvironment.getSource();
            String commodityId = order.getCommodityId();
            return Commodity.commoditys
                    .stream()
                    .filter(commodity -> commodity.getId().equals(commodityId))
                    .findFirst()
                    .orElse(null);
        };
    }

    public DataFetcher getCommodityByNameDataFetcher() {
        return dataFetchingEnvironment -> {
            String commodityName = dataFetchingEnvironment.getArgument("name");
            return Commodity.commoditys
                    .stream()
                    .filter(commodity -> commodity.getName().equals(commodityName))
                    .findFirst()
                    .orElse(null);
        };
    }

}

 

新建OrderController,提供数据查询接口。

package com.learn.controller;

import com.learn.service.GraphQLService;
import graphql.ExecutionResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @Autowired
    private GraphQLService graphQLService;

    @PostMapping("/crmdrt")
    public ResponseEntity<Object> getAllBooks(@RequestBody String query){
        ExecutionResult execute = graphQLService.getGraphQL().execute(query);
        return new ResponseEntity<>(execute, HttpStatus.OK);
    }

}

 

整个工程的代码就编写完了,整体的工程结构如下:


测试​​​​​​

将项目启动,通过postman访问http:localhost:8080/crmdrt对服务发起请求。

输入1:

{
   orderById(id: "order-1") {
        id customer commodity {name price}
    }
}

输出1:

{
    "errors": [],
    "data": {
        "orderById": {
            "id": "order-1",
            "customer": "张三",
            "commodity": {
                "name": "从入门到入土",
                "price": "20"
            }
        }
    },
    "extensions": null,
    "dataPresent": true
}

输入2:

{commodityByName(name: "从入门到入土") {name price}}

输出2:

{
    "errors": [],
    "data": {
        "commodityByName": {
            "name": "从入门到入土",
            "price": "20"
        }
    },
    "extensions": null,
    "dataPresent": true
}
参考文献:https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值