Skip to content

Commit 869ec98

Browse files
authored
Add dangerouslyDisableValidation option to @apollo/server (#7786)
This adds a `dangerouslyDisableValidation` option to `@apollo/server` which will skip the validation step for graphql operations.
1 parent 3fb036f commit 869ec98

6 files changed

Lines changed: 61 additions & 20 deletions

File tree

.changeset/blue-laws-grab.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@apollo/server-integration-testsuite': minor
3+
'@apollo/server': minor
4+
---
5+
6+
Restore missing v1 `skipValidation` option as `dangerouslyDisableValidation`. Note that enabling this option exposes your server to potential security and unexpected runtime issues. Apollo will not support issues that arise as a result of using this option.

docs/source/api/apollo-server.mdx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,21 @@ Apollo Server v5 will _always_ behave as if this option is `true` (and will igno
492492
</td>
493493
</tr>
494494

495+
<tr>
496+
<td>
497+
498+
##### `dangerouslyDisableValidation`
499+
500+
`Boolean`
501+
</td>
502+
<td>
503+
504+
⚠️ Caution: this option can lead to security vulnerabilities and unexpected behavior. Use of this option in production is not supported by Apollo.
505+
506+
When set to `true`, disable validation of graphql operations entirely.
507+
</td>
508+
</tr>
509+
495510
</tbody>
496511
</table>
497512

packages/integration-testsuite/src/apolloServerTests.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,21 @@ export function defineIntegrationTestSuiteApolloServerTests(
312312
);
313313
});
314314

315+
it('allows disabling validation rules', async () => {
316+
const uri = await createServerAndGetUrl({
317+
schema,
318+
stopOnTerminationSignals: false,
319+
nodeEnv: 'production',
320+
dangerouslyDisableValidation: true,
321+
});
322+
323+
const apolloFetch = createApolloFetch({ uri });
324+
325+
const result = await apolloFetch({ query: INTROSPECTION_QUERY });
326+
expect(result.data).toBeDefined();
327+
expect(result.errors).toBeUndefined();
328+
});
329+
315330
it('allows introspection to be enabled explicitly', async () => {
316331
const uri = await createServerAndGetUrl({
317332
schema,

packages/server/src/ApolloServer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ type ServerState =
155155
export interface ApolloServerInternals<TContext extends BaseContext> {
156156
state: ServerState;
157157
gatewayExecutor: GatewayExecutor | null;
158-
158+
dangerouslyDisableValidation?: boolean;
159159
formatError?: (
160160
formattedError: GraphQLFormattedError,
161161
error: unknown,
@@ -296,6 +296,8 @@ export class ApolloServer<in out TContext extends BaseContext = BaseContext> {
296296
...(config.validationRules ?? []),
297297
...(introspectionEnabled ? [] : [NoIntrospection]),
298298
],
299+
dangerouslyDisableValidation:
300+
config.dangerouslyDisableValidation ?? false,
299301
fieldResolver: config.fieldResolver,
300302
includeStacktraceInErrorResponses:
301303
config.includeStacktraceInErrorResponses ??

packages/server/src/externalTypes/constructor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ interface ApolloServerOptionsBase<TContext extends BaseContext> {
9797
apollo?: ApolloConfigInput;
9898
nodeEnv?: string;
9999
documentStore?: DocumentStore | null;
100+
dangerouslyDisableValidation?: boolean;
100101
csrfPrevention?: CSRFPreventionOptions | boolean;
101102

102103
// Used for parsing operations; unlike in AS3, this is not also used for

packages/server/src/requestPipeline.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -235,27 +235,29 @@ export async function processGraphQLRequest<TContext extends BaseContext>(
235235
}
236236
await parsingDidEnd();
237237

238-
const validationDidEnd = await invokeDidStartHook(
239-
requestListeners,
240-
async (l) =>
241-
l.validationDidStart?.(
242-
requestContext as GraphQLRequestContextValidationDidStart<TContext>,
243-
),
244-
);
245-
246-
const validationErrors = validate(
247-
schemaDerivedData.schema,
248-
requestContext.document,
249-
[...specifiedRules, ...internals.validationRules],
250-
);
238+
if (internals.dangerouslyDisableValidation !== true) {
239+
const validationDidEnd = await invokeDidStartHook(
240+
requestListeners,
241+
async (l) =>
242+
l.validationDidStart?.(
243+
requestContext as GraphQLRequestContextValidationDidStart<TContext>,
244+
),
245+
);
251246

252-
if (validationErrors.length === 0) {
253-
await validationDidEnd();
254-
} else {
255-
await validationDidEnd(validationErrors);
256-
return await sendErrorResponse(
257-
validationErrors.map((error) => new ValidationError(error)),
247+
const validationErrors = validate(
248+
schemaDerivedData.schema,
249+
requestContext.document,
250+
[...specifiedRules, ...internals.validationRules],
258251
);
252+
253+
if (validationErrors.length === 0) {
254+
await validationDidEnd();
255+
} else {
256+
await validationDidEnd(validationErrors);
257+
return await sendErrorResponse(
258+
validationErrors.map((error) => new ValidationError(error)),
259+
);
260+
}
259261
}
260262

261263
if (schemaDerivedData.documentStore) {

0 commit comments

Comments
 (0)