GraphQL使用
1. 介绍
GraphQL是一个开源的,面向API而创造出来的数据查询操作语言以及相应的运行环境。
GraphQL给客户端自主选择数据内容的能力,客户端完全自主决定获取信息的内容,服务端负责精确的返回目标数据。
我们经常会在某个需求中需要调用多个独立的API接口才能获取到足够的数据,例如客户端要去显示一篇文章的内容,同时也要显示评论、作者信息,那么就可能需要调用文章接口、评论接口、用户接口。这种方式非常的不灵活。另一个case是很多项目都会去拉一些不同的配置文件来决定展示什么,比如我们业务里的app,一打开就有10多个请求,非常不合理,不仅多个请求浪费了带宽,而且速度慢,客户端处理的请求也复杂。
2. graphql-server-demo服务端
2.1 graphql定义文件
player.graphqls
type Player { id: ID! name: String! points: Int! inventory: [Item!]! billing: Billing! } type Billing { balance: String! # decimal string... operations: [Operation!]! } type Operation { amount: String! # decimal string... description: String } type Item { name: String! } type Query { currentPlayer(id: ID!): Player! currentPlayerAll: [Player!]! }
2.2 调用4个独立API接口获取数据
@RequiredArgsConstructor class Player { private final Integer id; private final BillingRepository billingRepository; private final InventoryClient inventoryClient; private final PlayerMetadata playerMetadata; private final PointsCalculator pointsCalculator; CompletableFuture<Billing> billing() { return billingRepository.forUser(id); } CompletableFuture<String> name() { return playerMetadata.lookupName(id); } CompletableFuture<Integer> points() { return pointsCalculator.pointsOf(id); } CompletableFuture<List<Item>> inventory() { return inventoryClient.loadInventory(id); } }
2.3 API接口实现 - 获取player名称
@Component @RequiredArgsConstructor class PlayerMetadata { private final ExecutorService playerExecutor; private final Fairy fairy; CompletableFuture<String> lookupName(Integer playerId) { return CompletableFuture.supplyAsync(() -> { Sleeper.sleep(Duration.ofMillis(100)); return fairy.person().getFirstName()+"_id_"+playerId; }, playerExecutor); } }
3. graphql客户端
3.1 currentPlayerAll获取player数据列表
requestBody数据格式
{ currentPlayerAll { id name points inventory { name } billing { balance operations { amount description } } } }
@Log4j2 public class graplql_01 { private static final String CONTENT_TYPE = "application/graphql"; public static void main(String... args) throws Exception { String id = invokeRemoteService("currentPlayerAll",11L); log.info("--------, id = "+id); // String id2 = invokeRemoteService("currentPlayer",11L); // log.info("--------, id = "+id2); } private static String invokeRemoteService(String methodName, Long traceId) throws Exception { String url = "http://127.0.0.1:8080/graphql"; // create an instance of RestTemplate RestTemplate restTemplate = new RestTemplate(); // create headers HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.valueOf(CONTENT_TYPE));// set `content-type` header // request body parameters // build the request String requestBody = null; if("currentPlayerAll".equals(methodName)){ requestBody = readRequestBody(); }else if("currentPlayer".equals(methodName)){ requestBody = readRequestBodyById(); } HttpEntity<String> entity = new HttpEntity<>(requestBody, headers); // send POST request ResponseEntity<Object> response = restTemplate.postForEntity(url, entity, Object.class); // check response if (response.getStatusCode() == HttpStatus.CREATED || response.getStatusCode() == HttpStatus.OK) { log.info("Request [" + traceId + "] Successful 200 content = \n" + JSON.toJSONString(response.getBody(),true)); JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response.getBody())); JSONObject data = jsonObject.getJSONObject("data"); String ids = ""; if("currentPlayerAll".equals(methodName)){ JSONArray currentPlayers = data.getJSONArray(methodName); /**获取id列表**/ List<String> playerIds = Arrays.stream(currentPlayers.toArray()).map(f -> ((JSONObject)f).getString("id")).collect(Collectors.toList()); String playerIdsStr = playerIds.stream().collect(Collectors.joining("::")); ids = playerIdsStr; }else if("currentPlayer".equals(methodName)){ JSONObject currentPlayer = data.getJSONObject(methodName); ids = currentPlayer.getString("id"); } return ids; } else { log.info("Request [" + traceId + "] Failed [" + response.getStatusCode() + "] content = " + response.getBody()); return "-1"; } } private static String readRequestBody() throws URISyntaxException, IOException { Stream<String> lines = Files.lines( Paths.get(ClassLoader.getSystemResource("request_body.txt").toURI())); return lines.collect(Collectors.joining()); } private static String readRequestBodyById() throws URISyntaxException, IOException { Stream<String> lines = Files.lines( Paths.get(ClassLoader.getSystemResource("request_body2.txt").toURI())); return lines.collect(Collectors.joining()); } }
调用结果:
{ "data":{ "currentPlayerAll":[ { "id":"1315563916", "name":"Nicholas_id_1315563916", "points":42, "inventory":[ { "name":"Sword" }, { "name":"Sword" } ], "billing":{ "balance":"10", "operations":[ { "amount":"10", "description":"Item purchase" }, { "amount":"1", "description":"Item purchase" } ] } }, { "id":"269998305", "name":"Luke_id_269998305", "points":42, "inventory":[ { "name":"Shoes" }, { "name":"Shoes" } ], "billing":{ "balance":"10", "operations":[ { "amount":"10", "description":"Item purchase" }, { "amount":"1", "description":"Item purchase" } ] } } ] } }
3.2 currentPlayer获取某个ID对应的player数据
requestBody数据格式
{ currentPlayer(id: 11) { id name points inventory { name } billing { balance operations { amount description } } } }
调用结果:
{ "data":{ "currentPlayer":{ "id":"11", "name":"Aaron_id_11", "points":42, "inventory":[ { "name":"Potion" }, { "name":"Shoes" } ], "billing":{ "balance":"10", "operations":[ { "amount":"10", "description":"Item purchase" }, { "amount":"1", "description":"Item purchase" } ] } } } }
3.3 currentPlayer获取不同格式的player数据
requestBody数据格式
{ currentPlayer(id: 11) { id name points billing { balance operations { amount } } } }
调用结果:
{ "data":{ "currentPlayer":{ "id":"11", "name":"Allison_id_11", "points":42, "billing":{ "balance":"10", "operations":[ { "amount":"10" }, { "amount":"1" } ] } } } }
标签:String,private,id,amount,GraphQL,使用,currentPlayer,name From: https://www.cnblogs.com/sanqianyuejia/p/17010923.html