Apollo-link-rest: Fehler, wenn die REST-Antwort leer ist

Erstellt am 7. Mai 2018  ·  18Kommentare  ·  Quelle: apollographql/apollo-link-rest


Ich habe eine Mutationsanfrage, die bei Erfolg mit dem Status 204 "Kein Inhalt" antwortet. In Verbindung mit Apollo-Link-Fehler erhalte ich ständig einen Netzwerkfehler: Unerwartetes Ende der JSON-Eingabe .

Es scheint, dass Apollo-Link-Rest versucht, den leeren Körper der Antwort zu analysieren.

Irgendwelche Ideen, wie man das abmildern kann? Übrigens versuche ich, mit einer SharePoint REST-API zu sprechen, daher kann ich nicht viel tun, um die Antwort des Servers zu optimieren.

Es sollte eine Möglichkeit geben, dem Apollo-Link-Rest zu sagen, wie er mit einer leeren Antwort umgehen soll ...

Mein Mutationsaufruf:

                  <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>

Die entsprechende gql-Abfrage:

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" ist offensichtlich _null_, da es keine Antwort gibt, aber andererseits kann ich keine Mutation ohne Antwortfelder senden ... es sei denn, ich vermisse etwas.

enhancement💡 feature help wanted 🛠 question❔

Hilfreichster Kommentar

Ich denke, damit die vorgelagerte GraphQL-Interpretation des leeren Körpers funktioniert, sollten wir {} was dann dazu führt

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

Wenn Sie sagen "Könnten beide Verhaltensweisen unterstützt werden?" Meinen Sie damit den Statuscode 204 und die Überschriften? Ich denke, wenn das Content-Length tatsächlich vorhanden ist und auch 0 dann könnten wir das als einen weiteren Hinweis auf einen leeren Körper nehmen und den Standard zurückgeben.

Obwohl ich den Content-Type -Header früher vorgeschlagen habe, ist mir eigentlich nicht klar, was zu tun ist, wenn er auf etwas anderes als json . Ich denke, wenn dieser Header interpretiert werden soll, muss er wahrscheinlich mit einer responseSerializer Konfigurationsoption durchgeführt werden, die der vorgeschlagenen bodySerializer ähnelt. Das ist wahrscheinlich übertrieben und würde insbesondere das Problem des leeren Körpers nicht ansprechen.

Ich bin froh, die Implementierung von 204 und Content-Length durchführen zu können.

Alle 18 Kommentare

@isopterix - Ich glaube nicht, dass wir im {} - Ich denke, ohne eine bessere Funktion zu erstellen, ist dies die einzige Möglichkeit, dies zu tun heute!

@isopterix Ich habe versucht, dieses Problem mit dem folgenden Test zu reproduzieren, aber der Test besteht für einen leeren Körper. Es scheint, dass fetch response.json() {} zurückgibt, wenn der Body eine leere Zeichenfolge ist. Könnten Sie versuchen, dies in Ihrem Live-Setup genauer zu verfolgen, um festzustellen, wo der Fehler auftritt?

  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 egal mein letzter Kommentar. Es scheint, dass die Browser-Implementierungen weniger fehlerverzeihend sind als die Testumgebung.

Das einzige Problem, das ich beim Erkennen eines leeren Körpers sehe, ist, dass es keine sichere Möglichkeit gibt, zu erkennen, was sich im Körper befindet, ohne res.json() oder res.text() aufzurufen, und immer beide aufzurufen, nur für den Fall redundant. Andernfalls könnte man sich den Content-Length -Header ansehen, aber ich bin mir nicht sicher, ob er immer zuverlässig sein wird. Eine andere Option wäre, JSON nur zu analysieren, wenn Content-Type application/json ist. Es ist jedoch auch denkbar, dass einige APIs diesen Header für alle Antworten und sogar für eine leere Antwort gemeinsam festlegen.

Da der Rest-Link networkError jedem Statuscode über 300 ein

  • 200 OK
  • 201 Erstellt
  • 202 Akzeptiert
  • 204 Kein Inhalt
  • (einer der anderen?)

Die 204 Antworten sollten die einzigen sein, die einen leeren Körper haben. Wäre es eine Option, den Statuscode zu überprüfen und einen Standardwert von {} wenn er 204 ist? Dies wäre zwar ein Test für einen ganz bestimmten Randfall, würde jedoch die HTTP-Standard-Konformität der Bibliothek erhöhen, was eine gute Sache zu sein scheint.

@fbartho Würden Sie einen dieser Ansätze bevorzugen? Ich mache die PR, wenn eine dieser Optionen oder eine Kombination davon vernünftig klingt.

Vielleicht gibt es hier einen Mittelweg? Könnten beide Verhaltensweisen unterstützt werden?

Ich unterstütze es ziemlich, 204 standardmäßig selbst als {} zu interpretieren, oder als "null" ist null das semantische Äquivalent von keinem Inhalt in JSON?

Ich denke, damit die vorgelagerte GraphQL-Interpretation des leeren Körpers funktioniert, sollten wir {} was dann dazu führt

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

Wenn Sie sagen "Könnten beide Verhaltensweisen unterstützt werden?" Meinen Sie damit den Statuscode 204 und die Überschriften? Ich denke, wenn das Content-Length tatsächlich vorhanden ist und auch 0 dann könnten wir das als einen weiteren Hinweis auf einen leeren Körper nehmen und den Standard zurückgeben.

Obwohl ich den Content-Type -Header früher vorgeschlagen habe, ist mir eigentlich nicht klar, was zu tun ist, wenn er auf etwas anderes als json . Ich denke, wenn dieser Header interpretiert werden soll, muss er wahrscheinlich mit einer responseSerializer Konfigurationsoption durchgeführt werden, die der vorgeschlagenen bodySerializer ähnelt. Das ist wahrscheinlich übertrieben und würde insbesondere das Problem des leeren Körpers nicht ansprechen.

Ich bin froh, die Implementierung von 204 und Content-Length durchführen zu können.

Bisher habe ich den früheren Rat befolgt und einen benutzerdefinierten Abruf implementiert, um die 204-Antwort zu verarbeiten. Aber ich hatte Schwierigkeiten, eine richtige Antwort zurück zu bekommen. Die Option, diese Funktionalität sofort einsatzbereit zu machen, wäre fantastisch.

Leider lerne ich immer noch, wie man in der JS-Welt navigiert ...

Behoben über # 111!

Süss! Vielen Dank.

Jetzt gibt es nur noch ein kleines Problem :) Gleich nachdem ich meine eigene temporäre Lösung ausgearbeitet hatte, stieß ich auf ein weiteres Problem mit der REST-API meines SharePoint-Zielservers ... Wenn Sie einen Eintrag löschen, erhalten Sie eine Antwort von 200 ohne Körperinhalt :)

Könnten wir das Verhalten möglicherweise verallgemeinern, dh wenn kein Körperinhalt vorhanden ist, antworten Sie mit dem Tag "NoResponse"? Wenn ich mich nicht irre, befasst sich der Patch derzeit nur mit dem Sonderfall 204.

@isopterix Wenn der Server Content-Length richtig auf Null setzt, sollte er auch bei 200 Antworten funktionieren. Dies soll auch überprüft werden.

Ich freue mich darauf, es zu versuchen.

Deckt dies eine erfolgreiche Antwort mit leerem Inhalt ab? Wie eine 200 ohne Inhalt?

Ja. Der Fix, der für diesen Vorgang zusammengeführt wurde, sucht nach einem 204-Status oder einem Content-Length: 0 -Header und gibt ein leeres Objekt zurück.

Wenn Sie eine 200 leere Antwort ohne einen Content-Length -Header haben, funktioniert dies nicht, da der Body für diese Prüfung nicht analysiert wird.

@isopterix können Sie bestätigen, dass dies funktioniert? Ich versuche eine Mutation zu machen, die mir einen 200 Status und Content-Length: 0 . Ich bekomme jedoch immer noch ein Network error: Unexpected end of JSON input . Ich verwende Version 0.7.0.

Ich sehe, dass die Antwortheader beim Debuggen von apollo-link-rest leer sind, während mein Browser tatsächlich Header anzeigt. Manipuliert / setzt apollo-link-rest die Header im Antwortobjekt zurück?

Apollo-Link-Rest manipuliert keine Antwortheader @dljcollette! Ich hoffe, das hilft

Ich treffe den gleichen Fehler

Hat es eine Problemumgehung für Status 200 mit leerem Körper?

@thomaszdxsn Die einzige Möglichkeit, dies zu res.text() anstelle von res.json() und vor dem Parsen mit JSON.parse() nach gültigem JSON zu suchen. Dies bedeutet, dass Sie das Streaming von JSON-Parsing verlieren und als solches wahrscheinlich nichts getan wird.

Die beste Lösung wäre, Ihre API so zu ändern, dass sie den semantisch korrekten Statuscode 204 verwendet, wenn der Text leer ist, oder etwas im 200-Antworttext zurückzugeben. Ich denke, sogar ein leeres JSON-codiertes Objekt würde funktionieren, solange sich nur etwas im Antworttext befindet, das gültiges JSON ist.

Wenn Sie die API wirklich nicht ändern können, können Sie möglicherweise eine benutzerdefinierte fetch -Funktion an apollo-link-rest , wo Sie die Antwort überprüfen und ändern können, bevor Sie schließlich zur Verarbeitung von ALR zurückkehren. Es wird ein Hack sein, aber es könnte für Sie funktionieren.

Oder stellen Sie einfach sicher, dass die API den Content-length: 0 -Header in der Antwort zurückgibt.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen