如何在GraphQL中包含变异请求元数据?

时间:2018-08-30 15:42:02

标签: node.js graphql

我正在使用API​​后端从头开始构建GraphQL服务器,以取代REST API服务器。当前,现有API服务器中的一些请求(主要是创建/更新请求)将是GraphQL中的突变,其中包括客户端使用的请求ID。此请求ID是有关请求本身的元数据,而不是域资源的一部分。

我的问题是如何在GraphQL查询和变异中建模/包含请求元数据?到目前为止,我唯一的解决方案是创建一个请求类型,其他类型也可以将其作为字段包括在内,以便请求数据可以包含在变异返回类型中。但是我不喜欢这种方法,因为它将请求数据混合到我的域类型中,这在很大程度上与GraphQL的精神背道而驰。是否有通过``任意''的公认方法,例如GraphQL中查询或突变的响应中获取非域类型数据?

示例-我想避免的事情:

type UserType {
  id: ID
  name: String
  request: RequestType // mixing request data in with domain type of User
}

type RequestType {
  id: ID
}

更新

对于对此问题感兴趣的其他人,根据此处的响应,我认为GraphQL extensions键是在GraphQL响应中添加任意数据而不使数据成为数据Graph的一部分的好选择。在Express-GraphQL中,有关在响应中添加扩展键的文档,请参见:https://github.com/graphql/express-graphql#providing-extensions。这里的扩展概述:https://marmelab.com/blog/2017/09/06/dive-into-graphql-part-iii-building-a-graphql-server-with-nodejs.html#server-logging

也就是说,如果请求元数据从概念上讲是域数据的一部分,则遵循Kashif的以下建议,即创建嵌入域类型的ResponseTypes可能是正确的方法。

2 个答案:

答案 0 :(得分:0)

这种元元素通常随每个请求传递到HEADERS中。然后,您可以根据需要在GraphQL服务器中处理这些问题

例如。

//Request Headers
...

X-Request-Id: <Your_Request_Id>

...

更新

标头可以双向工作,因此在客户端上使用标头也不会有任何问题。随时根据需要将它们拉出响应。

但是,如果您确实希望您的突变响应中包含requestId,那么这就是您域的一部分。拥有自定义响应类型没有什么问题,许多现有的GraphQL api确实具有自定义响应类型,例如LoginResponseRegisterResponse,它会包裹您的域对象,但在{{1 }}字段

答案 1 :(得分:0)

由于GraphQL被设计为与协议无关,因此您应该使用所选协议的元数据模式。如果使用的是HTTP,则应传递标头。如果您使用的是WS / STOMP / MQTT / AMQP,则可以在每个帧中包含元数据。

或者GraphQL有一个extensions protocol。您可以在扩展对象中的响应中添加import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { Map<String, String> textMessageMap = {'message': 'Home'}; @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( '${textMessageMap != null ? textMessageMap['message'] : 'map is null'}', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: new FloatingActionButton( onPressed: () { _launchSecondScreen(); }, child: new Icon(Icons.add), ), ); } _launchSecondScreen() async { final value = await Navigator.push( context, MaterialPageRoute<Map<String, String>>( builder: (BuildContext _) => SecondScreen())); setState(() { textMessageMap = value; }); } } class SecondScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Screen"), ), body: Center( child: RaisedButton( onPressed: () { // Navigate back to the first screen by popping the current route // off the stack. The text 'Second Screen' will replace 'Home'. // If you hit the scaffold's back button, the return value will be // null instead. final map = {'message': 'Second Screen'}; Navigator.pop(context, map); }, child: Text('Go back!'), ), ), ); } } 。 Apollo使用扩展进行缓存,遥测等。

我们已经在生产中使用GraphQL大约一年了,我们犯了将元数据添加到GraphQL中的错误,并且变得难以管理。不要失去正在使用的协议功能的好处。