普通的REST API可能会让您使用不同的Accept
标头(例如, application/json
或text/html
或text/csv
格式的响应。
但是,如果您使用的是GraphQL,似乎JSON是唯一可接受的返回内容类型。但是,我需要我的API能够返回CSV数据,以供不了解JSON的不太成熟的客户端使用。
如果给定Accept: text/csv
头,那么GraphQL端点返回CSV数据是否有意义?如果没有,是否有更好的实践方法?
这更多是一个概念性问题,但是我专门使用Graphene来实现我的API。是否提供任何处理自定义内容类型的机制?
答案 0 :(得分:1)
是的,你可以,但它不是内置的,你必须覆盖一些东西。这更像是一种解决方法。
采取这些步骤,您将获得 csv 输出:
将 csv = graphene.String()
添加到您的查询中并将其解析为您想要的任何内容。
创建一个继承 GraphQLView
覆盖 dispatch
函数如下:
def dispatch(self, request, *args, **kwargs):
response = super(CustomGraphqlView, self).dispatch(request, *args, **kwargs)
try:
data = json.loads(response.content.decode('utf-8'))
if 'csv' in data['data']:
data['data'].pop('csv')
if len(list(data['data'].keys())) == 1:
model = list(data['data'].keys())[0]
else:
raise GraphQLError("can not export to csv")
data = pd.json_normalize(data['data'][model])
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="output.csv"'
writer = csv.writer(response)
writer.writerow(data.columns)
for value in data.values:
writer.writerow(value)
except GraphQLError as e:
raise e
except Exception:
pass
return response
导入所有必要的模块
用新的视图类替换 GraphQLView
文件中的默认 urls.py
。
现在,如果您在 GraphQL 查询中包含“csv”,它将返回原始 csv 数据,然后您可以将数据保存到前端的 csv 文件中。示例查询类似于:
query{
items{
id
name
price
category{
name
}
}
csv
}
请记住,这是一种以 csv 格式获取原始数据的方法,您必须保存它。您可以使用以下代码在 JavaScript 中执行此操作:
req.then(data => {
let element = document.createElement('a');
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(data.data));
element.setAttribute('download', 'output.csv');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
})
这种方法将 JSON 数据展平,因此不会丢失任何数据。
答案 1 :(得分:0)
GraphQL依赖于(并因此而发光)响应嵌套数据。据我了解,CSV只能显示平面键值对。这使得CSV不太适合GraphQL响应。
我认为实现您想要做的最干净的方法是将GraphQL客户端放在您的客户端之前:
+------+ csv +-------+ http/json +------+
|client|<----->|adapter|<----------->|server|
+------+ +-------+ +------+
这里的好处是您的适配器只需要将其指定的查询转换为CSV。
显然,您可能并不总是能够这样做(但是您如何使他们发送GraphQL查询)。或者,您可以构建将JSON转换为CSV的中间件。但是然后您必须处理整个GraphQL规范。祝你好运,翻译此回复:
{
"__typename": "Query",
"someUnion": [
{ "__typename": "UnionA", "numberField": 1, "nested": [1, 2, 3, 4] },
{ "__typename": "UnionB", "stringField": "str" },
],
"otherField": 123.34
}
因此,如果您无法解决通过HTTP传输CSV的问题,那么GraphQL就是错误的选择,因为它不是为此而构建的。而且,如果您不允许那些难以转换为CSV的GraphQL功能,那么您就不再具有GraphQL,因此没有必要再将其称为GraphQL。