From 079fae1d18d72d991979d31d8e9df491ad6d52f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sant=C3=A1ngelo?= Date: Thu, 9 Jun 2022 20:26:35 -0300 Subject: [PATCH 1/2] feat: support single error message --- src/index.ts | 16 ++++++++-------- src/types.ts | 7 ++++++- test/component.spec.ts | 29 +++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/index.ts b/src/index.ts index aa4ef11..465cb7c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -47,15 +47,15 @@ export async function createSubgraphComponent( timeoutWait ) + const hasErrors = errors !== undefined + if (hasErrors) { + const errorMessages = Array.isArray(errors) ? errors.map((error) => error.message) : [errors.message] + throw new Error(`GraphQL Error: Invalid response. Errors:\n- ${errorMessages.join("\n- ")}`) + } + const hasInvalidData = !data || Object.keys(data).length === 0 - const hasMultipleErrors = errors && errors.length > 1 - - if (hasInvalidData || hasMultipleErrors) { - throw new Error( - hasMultipleErrors - ? `There was a total of ${errors.length}. GraphQL errors:\n- ${errors.join("\n- ")}` - : "GraphQL Error: Invalid response" - ) + if (hasInvalidData) { + throw new Error("GraphQL Error: Invalid response.") } logger.info("Success:", logData) diff --git a/src/types.ts b/src/types.ts index c086e81..68e1653 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,7 +6,12 @@ export type Variables = Record = { data: T; errors?: { message: string }[] } +export type Error = { message: string } + +/** + * @public + */ +export type SubgraphResponse = { data: T; errors?: Error[] | Error } /** * @public diff --git a/test/component.spec.ts b/test/component.spec.ts index 03bdde2..d58bf3b 100644 --- a/test/component.spec.ts +++ b/test/component.spec.ts @@ -2,7 +2,7 @@ import { ILoggerComponent } from "@well-known-components/interfaces" import { IFetchComponent } from "@well-known-components/http-server" import { randomUUID } from "crypto" import { setTimeout } from "timers/promises" -import { ISubgraphComponent } from "../src/types" +import { ISubgraphComponent, SubgraphResponse } from "../src/types" import { createSubgraphComponent } from "../src" import { SUBGRAPH_URL, test } from "./components" @@ -79,7 +79,7 @@ test("subraph component", function ({ components, stubComponents }) { }) describe("when the request errors out", () => { - let errorResponseData: { errors: string[] } + let errorResponseData: SubgraphResponse describe("and the server has an internal error", () => { beforeEach(() => { @@ -162,10 +162,15 @@ test("subraph component", function ({ components, stubComponents }) { }) describe("when the query is incorrect", () => { + const errorMessage = "No suitable indexer found for subgraph deployment" + beforeEach(() => { const { fetch } = components - errorResponseData = { errors: [] } + errorResponseData = { + data: undefined, + errors: { message: errorMessage }, + } response = { ok: true, status: 400, @@ -185,28 +190,36 @@ test("subraph component", function ({ components, stubComponents }) { expect(metrics.increment).toHaveBeenCalledWith("subgraph_errors_total", { url: SUBGRAPH_URL, - errorMessage: "GraphQL Error: Invalid response", + errorMessage: `GraphQL Error: Invalid response. Errors:\n- ${errorMessage}`, }) }) describe("and there's an empty errors prop", () => { + beforeEach(() => { + errorResponseData = { + data: {}, + errors: undefined, + } + }) + it("should throw an Invalid Response error", async () => { const { subgraph } = components - await expect(subgraph.query("query", {}, 0)).rejects.toThrow("GraphQL Error: Invalid response") + await expect(subgraph.query("query", {}, 0)).rejects.toThrow("GraphQL Error: Invalid response.") }) }) describe("and there's multiple errors", () => { beforeEach(() => { errorResponseData = { - errors: ["some error", "happened"], + data: undefined, + errors: [{ message: "some error" }, { message: "happened" }], } }) it("should throw them all", async () => { const { subgraph } = components await expect(subgraph.query("query", {}, 0)).rejects.toThrow( - "There was a total of 2. GraphQL errors:\n- some error\n- happened" + "GraphQL Error: Invalid response. Errors:\n- some error\n- happened" ) }) }) @@ -242,7 +255,7 @@ test("subraph component", function ({ components, stubComponents }) { expect(metrics.increment).toHaveBeenCalledTimes(retries + 1) expect(metrics.increment).toHaveBeenCalledWith("subgraph_errors_total", { url: SUBGRAPH_URL, - errorMessage: "GraphQL Error: Invalid response", + errorMessage: `GraphQL Error: Invalid response. Errors:\n- ${errorMessage}`, }) }) }) From 1a25f46875bfdd8830bacdaa34e62ddc3fd142c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sant=C3=A1ngelo?= Date: Thu, 9 Jun 2022 20:31:10 -0300 Subject: [PATCH 2/2] chore: api extractor --- etc/thegraph-component.api.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/etc/thegraph-component.api.md b/etc/thegraph-component.api.md index 962c867..27b9b74 100644 --- a/etc/thegraph-component.api.md +++ b/etc/thegraph-component.api.md @@ -23,6 +23,12 @@ export namespace createSubgraphComponent { }; } +// @public (undocumented) +type Error_2 = { + message: string; +}; +export { Error_2 as Error } + // @public (undocumented) export interface ISubgraphComponent { query: (query: string, variables?: Variables, remainingAttempts?: number) => Promise; @@ -42,9 +48,7 @@ export const metricDeclarations: IMetricsComponent.MetricsRecordDefinition = { data: T; - errors?: { - message: string; - }[]; + errors?: Error_2[] | Error_2; }; // @public (undocumented)