400 对 GraphQL 端点的错误请求(我的测试查询有啥问题?)

Posted

技术标签:

【中文标题】400 对 GraphQL 端点的错误请求(我的测试查询有啥问题?)【英文标题】:400 Bad Requst to GraphQL endpoint (What's wrong with my test's query?)400 对 GraphQL 端点的错误请求(我的测试查询有什么问题?) 【发布时间】:2020-04-06 18:46:04 【问题描述】:

我主要关注关于 how to create a mutation 的 GraphQL 文档。这是我使用 GraphQL 的第一天。我想为 cmets 创建一个端点。

隔离问题

我在 Mocha 中从我的 supertest 返回 400 "Bad Request",当我尝试运行 GraphiQL 时,它在错误数组中给我一条消息,上面写着“查询根必须提供类型。” ...但我包括rootValue

问题可能出在buildSchema

// imports (...working fine)

// Comment Interface for TypeScript is here ...and working
// ...

// gaphql schema (The problem could be here.)
const schema = buildSchema(`
    input CommentInput 
        _id: String
        author: String
        text: String
    
    type Comment 
        _id: String
        author: String
        text: String
    
    type Mutation 
        createOrUpdateComment(input: CommentInput): Comment
    
`);

// rootValue
const root = 
    createOrUpdateComment: (input:  input: IComment ) => 
       return 
         _id: "id here",
         author: input.author,
         text: input.text
       
    
;

export default graphqlHTTP(
    graphiql: true,
    rootValue: root,
    schema
);

这被导入,然后在快递服务器的顶层使用,就像comments这样:

app.use("/comments", comments);

工作原理:GraphiQL 确实会在浏览器中的localhost:8080/comments 处弹出,所以我很确定在 Express 方面没有问题。 (顺便说一句,TypeScript 编译得很好。)我还有一个不同的 GraphQL api 端点,它返回“Hello world!”在我使用 Mocha 测试的服务器的顶层并且它通过了(在它最初失败之后),所以我的测试套件似乎运行良好。没有额外的环境变量。这就是你在这里看到的。

我想通过的测试,给我 404 错误请求是:

// imports (...working fine)

describe("graphQl comments test", () => 

    it("should add a comment", (done) => 

        const query = `mutation createOrUpdateComment($input: CommentInput) 
              _id
              author
              text
          `;

        const variables = 
              input: 
                  author: "Brian",
                  text: "This is my favorite video of all time."
              
          ;

        request(app)
            .post("/comments")
            .send(JSON.stringify( query, variables)) // (The problem could be here.)
            .expect(200)
            .end((err, res) => 
                if (err)  return done(err); 
                // tslint:disable-next-line: no-unused-expression
                expect(res.body.data.id).to.exist;
                expect(res.body.data.author).to.equal("Brian");
                expect(res.body.data.text).to.equal("This is my favorite video of all time.");
                done();
            );
    );
);

既然它说的是“bad request”,那么我在测试中处理queryvariables 的方式肯定是问题所在。

问题

我的问题是测试中的查询和变量还是我的buildSchema? ...或者两者兼而有之?我将如何以不同的方式编写以使测试通过?

更新

在我将导出中的 rootValue 注释掉之后,就像这样,因为它在 GraphiQL 中说“必须提供查询根类型”,所以我发现没有区别。好像rootValue 不存在,即使它存在。

export default graphqlHTTP(
    graphiql: true,
    // rootValue: root,
    schema
);

一旦我根据this Github issue 中提到的内容添加了QuerygetComment()GraphiQL 中的错误消息就消失了。不幸的是,测试仍然给出 400 Bad Request,所以这些问题似乎无关。

更新 2

我使用 GraphiQL 测试了我的端点,当我发布时它按预期/期望运行:

mutation 
  createOrUpdateComment(input: _id: "4", author: "Some Author", text: "some unique text") 
    _id
    author
    text
  

我正在努力使我的测试查询类似,但它们不是类似物。这清楚地表明问题出在测试本身,当我记录正文的响应时,我得到了这个:

所以我的测试查询字符串有问题。

已解决。

请看下面我的回答。

【问题讨论】:

【参考方案1】:

我在测试中的主要问题是

我正在 JSON.stringifying 数据。那是在文档的example using fetch 中,但 supertest 会自动将数据转换为 JSON 字符串。 我将查询调整为只有一个没有添加变量的字符串。我想尽快尝试一下,看看是否可以将其与变量一起发送,但我只是想简化一些事情。 根据 Daniel Rarden 的建议,我注销了尸体。这是一个无价的调试建议,我没想到在测试中这样做,因为我只是假设,“嗯,它出错了,对吗?”呃。没有。总会有回应。这有助于我正确设置返回值。

这是我最终得到的测试文件:

import  expect  from "chai";
import request = require("supertest");
import app from "../src";

describe("graphQl comments test", () => 

    it("should add a comment", (done) => 

        const query = `mutation 
            createOrUpdateComment(input: _id: "4", author: "Brian", text: "This is my favorite video of all time.") 
              _id
              author
              text
            
          `;

        request(app)
            .post("/comments")
            .send(query)
            .expect(200)
            .end((err, res) => 
                if (err)  return done(err); 
                // tslint:disable-next-line: no-unused-expression
                expect(res.body.data.createOrUpdateComment._id).to.exist;
                expect(res.body.data.createOrUpdateComment.author).to.equal("Brian");
                expect(res.body.data.createOrUpdateComment.text).to.equal("This is my favorite video of all time.");
                done();
            );
    );
);

【讨论】:

【参考方案2】:

GraphQL 中有三种操作——查询、突变和订阅。每个操作都有一个与之关联的对象类型。这些被称为根类型。默认情况下,这些根类型分别命名为 QueryMutationSubscription(名称无关紧要,可以根据您的特定模式进行更改,但这些是默认值)。根类型作为入口点,或 root,用于对它进行的任何查询。

查询根类型是规范必需的,而其他两种根类型是可选的,可以省略。

该错误与 根值 无关。事实上,你可能shouldn't be using buildSchema and rootValue in the first place。如错误所示,您尚未在架构中提供查询根类型。您的架构包含的唯一根类型是 Mutation。您需要添加Query 以解决错误。

【讨论】:

你是对的。感谢您的关注。查看我的更新。 我将离开 buildSchema。看起来 GraphQL 需要更新他们的文档。我只是想让一个测试合法地通过。 @GabrielKunkel 即使它是 400 状态,仍然会有一个响应正文,您可以在测试中解析以确定错误的确切原因。但是,将确切的查询和变量复制并粘贴到 GraphiQL 中也会重现错误消息。 是的,我很快就会为问题添加更新,因为 GraphQL 似乎工作正常,但测试本身却没有,因为当我从 GraphiQL 运行突变时它工作了。

以上是关于400 对 GraphQL 端点的错误请求(我的测试查询有啥问题?)的主要内容,如果未能解决你的问题,请参考以下文章

源 GraphQL API:HTTP 错误 400 错误请求

Angular / Nest / GraphQL - 无法上传文件(400 错误请求或 500)

来自下一个 js 应用程序的 Graphql 400 错误请求?

React Apollo GraphQL Mutation 返回 400(错误请求)

所有 apollo 查询错误都会引发网络 400 错误

应用脚本 Shopify GraphQL 请求 - 400 响应