Skip to content

Commit

Permalink
Create specific error class to signal uplink fetcher errors (#1473)
Browse files Browse the repository at this point in the history
  • Loading branch information
nogates authored and trevor-scheer committed Feb 9, 2022
1 parent c6250a2 commit f5c2eb1
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 34 deletions.
2 changes: 1 addition & 1 deletion gateway-js/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This CHANGELOG pertains only to Apollo Federation packages in the `0.x` range. T

> The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the appropriate changes within that release will be moved into the new section.
- _Nothing yet! Stay tuned._
- Use specific error classes when throwing errors due Apollo Uplink being unreacheable or returning an invalid response [PR #1473](https://github.com/apollographql/federation/pull/1473)

## v0.48.0

Expand Down
3 changes: 3 additions & 0 deletions gateway-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1144,3 +1144,6 @@ export {
SupergraphSdlHook,
SupergraphManager
} from './config';

export { UplinkFetcherError } from "./supergraphManagers"

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
loadSupergraphSdlFromStorage,
loadSupergraphSdlFromUplinks
loadSupergraphSdlFromUplinks,
UplinkFetcherError,
} from '../loadSupergraphSdlFromStorage';
import { getDefaultFetcher } from '../../..';
import {
Expand Down Expand Up @@ -86,8 +87,10 @@ describe('loadSupergraphSdlFromStorage', () => {
compositionId: "originalId-1234",
maxRetries: 1
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 500 Internal Server Error",
)
);
})

Expand All @@ -105,8 +108,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"
)
);
});

Expand All @@ -129,7 +134,9 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowError(message);
).rejects.toThrowError(
new UplinkFetcherError(`An error occurred while fetching your schema from Apollo: \n${message}`)
);
});

it("throws on non-OK status codes when `errors` isn't present in a JSON response", async () => {
Expand All @@ -146,8 +153,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"
)
);
});

Expand All @@ -166,8 +175,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
)
);
});

Expand All @@ -185,8 +196,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input",
)
);
});

Expand All @@ -204,8 +217,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 413 Payload Too Large"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 413 Payload Too Large",
)
);
});

Expand All @@ -223,8 +238,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity",
)
);
});

Expand All @@ -242,8 +259,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 408 Request Timeout"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 408 Request Timeout",
)
);
});
});
Expand All @@ -263,8 +282,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout",
)
);
});

Expand All @@ -282,8 +303,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response",
)
);
});

Expand All @@ -301,8 +324,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 502 Bad Gateway"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 502 Bad Gateway",
)
);
});

Expand All @@ -320,8 +345,10 @@ describe('loadSupergraphSdlFromStorage', () => {
fetcher,
compositionId: null,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"An error occurred while fetching your schema from Apollo: 503 Service Unavailable"`,
).rejects.toThrowError(
new UplinkFetcherError(
"An error occurred while fetching your schema from Apollo: 503 Service Unavailable",
)
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ const fetchErrorMsg = "An error occurred while fetching your schema from Apollo:

let fetchCounter = 0;

export class UplinkFetcherError extends Error {
constructor(message: string) {
super(message);
this.name = 'UplinkFetcherError';
}
}

export async function loadSupergraphSdlFromUplinks({
graphRef,
apiKey,
Expand Down Expand Up @@ -132,7 +139,7 @@ export async function loadSupergraphSdlFromStorage({
fetcher,
});

throw new Error(fetchErrorMsg + (e.message ?? e));
throw new UplinkFetcherError(fetchErrorMsg + (e.message ?? e));
}

const endTime = new Date();
Expand All @@ -143,27 +150,27 @@ export async function loadSupergraphSdlFromStorage({
response = await result.json();
} catch (e) {
// Bad response
throw new Error(fetchErrorMsg + result.status + ' ' + e.message ?? e);
throw new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + e.message ?? e);
}

if ('errors' in response) {
throw new Error(
throw new UplinkFetcherError(
[fetchErrorMsg, ...response.errors.map((error) => error.message)].join(
'\n',
),
);
}
} else {
await submitOutOfBandReportIfConfigured({
error: new Error(fetchErrorMsg + result.status + ' ' + result.statusText),
error: new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + result.statusText),
request,
endpoint: errorReportingEndpoint,
response: result,
startedAt: startTime,
endedAt: endTime,
fetcher,
});
throw new Error(fetchErrorMsg + result.status + ' ' + result.statusText);
throw new UplinkFetcherError(fetchErrorMsg + result.status + ' ' + result.statusText);
}

const { routerConfig } = response.data;
Expand All @@ -177,10 +184,10 @@ export async function loadSupergraphSdlFromStorage({
} else if (routerConfig.__typename === 'FetchError') {
// FetchError case
const { code, message } = routerConfig;
throw new Error(`${code}: ${message}`);
throw new UplinkFetcherError(`${code}: ${message}`);
} else if (routerConfig.__typename === 'Unchanged') {
return null;
} else {
throw new Error('Programming error: unhandled response failure');
throw new UplinkFetcherError('Programming error: unhandled response failure');
}
}
1 change: 1 addition & 0 deletions gateway-js/src/supergraphManagers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { LocalCompose } from './LocalCompose';
export { LegacyFetcher } from './LegacyFetcher';
export { IntrospectAndCompose } from './IntrospectAndCompose';
export { UplinkFetcher } from './UplinkFetcher';
export { UplinkFetcherError } from './UplinkFetcher/loadSupergraphSdlFromStorage'

0 comments on commit f5c2eb1

Please sign in to comment.