Apollo-link-rest: REST応答が空の場合のエラー

作成日 2018年05月07日  ·  18コメント  ·  ソース: apollographql/apollo-link-rest


成功すると204の「コンテンツなし」ステータスで応答するミューテーションリクエストがあります。 apollo-link-errorと組み合わせると、常にネットワークエラーが発生します: JSON入力の予期しない終了

apollo-link-restが応答の空の本体を解析しようとしているようです。

これを軽減する方法はありますか? ところで、SharePoint REST APIと通信しようとしているので、サーバーの応答を微調整することはあまりできません。

空の応答を処理する方法をapollo-link-restに指示する方法があるはずです...

私の突然変異の呼びかけ:

                  <Mutation mutation={M_WRITE_PROJECT_DETAILS}>
                    {(writeProjectDetails, { data }) => (
                      <Form.Button
                        content="Save"
                        onClick={() => {
                          const token = localStorage.getItem("token");
                          writeProjectDetails({
                            variables: {
                              projectId: project.Id,
                              input: {
                                __metadata: {
                                  type: "SP.Data.ProjectListItem"
                                },
                                Title: project.Title
                              }
                            },
                            context: {
                              headers: {
                                "X-RequestDigest": token,
                                "X-HTTP-Method": "MERGE",
                                "IF-MATCH": "*"
                              }
                            }
                          });
                        }}
                      />
                    )}
                  </Mutation>

対応するgqlクエリ:

const M_WRITE_PROJECT_DETAILS = gql`
  mutation writeToSPList($projectId: String, $input: String) {
    writeToSPList(projectId: $projectId, input: $input)
      @rest(
        type: "Project"
        path: "/web/lists/GetByTitle('Projects')/items(:projectId)"
        method: "POST"
      ) {
      NoResponse
    }
  }
`;

「NoResponse」は、応答がないため明らかに_null_ですが、応答フィールドがないとミューテーションを送信できません...何かが足りない場合を除きます。

enhancement💡 feature help wanted 🛠 question❔

最も参考になるコメント

空のボディのアップストリームGraphQL解釈が機能するためには、 {}を返す必要があると思います。

data: {
  __typename: "...",
  NoResponse: null,
}

「両方の動作をサポートできますか?」と言うとき 204ステータスコードとヘッダーを確認するという意味ですか? Content-Lengthが実際に存在し、 0も存在する場合、それを空の本体の別の指標と見なして、デフォルトを返すことができると思います。

以前にContent-Typeヘッダーを提案しましたが、実際には、 json以外に設定されたときに何をすべきかが明確ではありません。 このヘッダーを解釈する場合は、提案されているbodySerializerと同様のresponseSerializerオプションを使用して実行する必要があると思います。 それはおそらくやり過ぎであり、特に空の体の問題には対処しません。

204とContent-Lengthの実装ができてうれしいです。

全てのコメント18件

@ isopterix-現時点では、これに対処する簡単な方法はないと思います。 -私の最初の考えは、Fetchをラップして、204個の応答の本文を{}置き換えるカスタムFetch実装を提供することをお勧めすることです-より良い機能を構築せずに、それが私がこれを行うことができる唯一の方法だと思います今日!

@isopterix以下のテストでこの問題を再現しようとしましたが、テストは空のボディで合格しました。 本文が空の文字列の場合、fetch response.json(){}返すようです。 ライブセットアップでこれをより詳細に追跡して、エラーが発生する場所を確認してみてください。

  describe('response parsing', () => {
    it('supports empty response bodies', async () => {
      expect.assertions(1);

      const link = new RestLink({ uri: '/api' });

      fetchMock.post('/api/posts', {
        status: 204,
        body: '',
      });

      const mutation = gql`
        mutation postEmptyResponse($input: String!) {
          newPost(input: $input)
            @rest(type: "Post", path: "/posts", method: "POST") {
            NoResponse
          }
        }
      `;
      const {data} = await makePromise<Result>(
        execute(link, {
          operationName: 'postEmptyResponse',
          query: mutation,
          variables: { input: 'Love apollo' },
        }),
      );

      expect(data).toEqual({
        newPost: {
          NoResponse: null,
          __typename: 'Post',
        }
      });
    });
  });

@isopterixは私の最後のコメントを気にしません。 ブラウザの実装は、テスト環境よりも寛容ではないようです。

空のボディを検出する際に私が目にする問題の1つは、 res.json()またはres.text()を呼び出さずにボディに何があるかを判断する確実な方法がなく、万が一の場合に備えて常に両方を呼び出すことです。冗長。 そうでなければ、 Content-Lengthヘッダーを見るかもしれませんが、それが常に信頼できるかどうかはわかりません。 別のオプションは、 Content-Typeapplication/json場合にのみJSONを解析することですが、一部のAPIは、すべての応答に共通のヘッダーを設定し、空の204応答にも設定する可能性があります。

残りのリンクは300を超えるステータスコードでnetworkErrorを生成するため、応答解析は2xxステータスコードを正しく処理するために十分に特殊化する必要があります。 遭遇することが合理的に予想されるもののうち、次のとおりです。

  • 200 OK
  • 201作成済み
  • 202承認済み
  • 204コンテンツなし
  • (他のどれか?)

204の応答は、空の本文を持つ唯一の応答である必要があります。 ステータスコードを調べて、204のときにデフォルトの{}を返すオプションはありますか? これは非常に特殊なエッジケースのテストですが、ライブラリをよりHTTP標準に準拠させるため、良いことのように思われます。

@fbarthoこれらのアプローチのいずれかを好みますか? これらのオプションの1つ、またはそれらの組み合わせが妥当と思われる場合は、PRを作成します。

おそらくここに中道がありますか? 両方の動作をサポートできますか?

私は204をデフォルトで{}として解釈することをかなり支持していますか、それとも「null」はnullであり、JSONにコンテンツがないことと意味的に同等ですか?

空のボディのアップストリームGraphQL解釈が機能するためには、 {}を返す必要があると思います。

data: {
  __typename: "...",
  NoResponse: null,
}

「両方の動作をサポートできますか?」と言うとき 204ステータスコードとヘッダーを確認するという意味ですか? Content-Lengthが実際に存在し、 0も存在する場合、それを空の本体の別の指標と見なして、デフォルトを返すことができると思います。

以前にContent-Typeヘッダーを提案しましたが、実際には、 json以外に設定されたときに何をすべきかが明確ではありません。 このヘッダーを解釈する場合は、提案されているbodySerializerと同様のresponseSerializerオプションを使用して実行する必要があると思います。 それはおそらくやり過ぎであり、特に空の体の問題には対処しません。

204とContent-Lengthの実装ができてうれしいです。

これまでのところ、私は以前のアドバイスに従い、204応答を処理するためにカスタムフェッチを実装しました。 しかし、私は適切な応答を取り戻すのに苦労しました。 この機能をすぐに使用できるオプションがあると便利です。

残念ながら、私はまだJSの世界をナビゲートする方法を学んでいます...

#111で修正!

甘い! どうもありがとうございました。

さて、まだ残っている小さな問題は1つだけです:)自分の一時的な解決策を考え出した直後に、ターゲットSharePointServerのRESTAPIでさらに別の問題が発生しました...エントリを削除すると、200の応答が返されますボディコンテンツなし:)

動作を一般化できる可能性がありますか。つまり、本文のコンテンツが「NoResponse」タグで応答しない場合はどうでしょうか。 私が間違っていない場合、パッチは現在、204の特殊なケースのみに対応しています。

@isopterixサーバーがContent-Lengthを適切にゼロに設定した場合、200の応答でも機能するはずです。その目的は、それもチェックすることです。

それを試してみるのを楽しみにしています。

これは、空のコンテンツで成功した応答をカバーしますか? コンテンツのない200のように?

はい。 このためにマージされた修正は、204ステータスまたはContent-Length: 0ヘッダーをチェックし、空のオブジェクトを返します。

Content-Lengthヘッダーのない200の空の応答がある場合、このチェックのために本文が解析されないため、機能しません。

@isopterixこれが機能することを確認できますか? 200ステータスとContent-Length: 0を与えるミューテーションを実行しようとしています。 ただし、まだNetwork error: Unexpected end of JSON inputます。 私はバージョン0.7.0を使用しています。

apollo-link-restデバッグすると、ブラウザに実際にヘッダーが表示されているのに、応答ヘッダーが空になっていることがわかります。 apollo-link-restは、応答オブジェクトのヘッダーを操作/リセットしますか?

Apollo-link-restは応答ヘッダー@dljcolletteを操作しません! それが役立つことを願っています

私は同じエラーに遭遇します

空のボディでステータス200の回避策はありますか?

それに対応するための唯一の方法は、使用することです@thomaszdxsn res.text()の代わりにres.json()して解析する前に、有効なJSONをチェックJSON.parse() 。 これは、ストリーミングJSON解析を緩めることを意味し、そのため、実行される可能性は低いです。

最善の解決策は、本文が空のときに意味的に正しいステータスコード204を使用するようにAPIを変更するか、200応答本文で何かを返すことです。 応答本文に有効なJSONであるものがあれば、空のJSONエンコードオブジェクトでも機能すると思います。

APIを本当に変更できない場合は、カスタムのfetch関数をapollo-link-rest渡して、最終的にALRに戻って処理する前に、応答を調べて変更することができます。 それはハックになるでしょうが、それはあなたのために働くかもしれません。

または、APIが応答でContent-length: 0ヘッダーを返すことを確認してください。

このページは役に立ちましたか?
0 / 5 - 0 評価