diff --git a/.changeset/blue-laws-grab.md b/.changeset/blue-laws-grab.md
new file mode 100644
index 00000000000..6e261ee15e5
--- /dev/null
+++ b/.changeset/blue-laws-grab.md
@@ -0,0 +1,6 @@
+---
+'@apollo/server-integration-testsuite': minor
+'@apollo/server': minor
+---
+
+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.
diff --git a/docs/source/api/apollo-server.mdx b/docs/source/api/apollo-server.mdx
index eed454115b8..e1522cacdb1 100644
--- a/docs/source/api/apollo-server.mdx
+++ b/docs/source/api/apollo-server.mdx
@@ -492,6 +492,21 @@ Apollo Server v5 will _always_ behave as if this option is `true` (and will igno
+
+
+
+##### `dangerouslyDisableValidation`
+
+`Boolean`
+ |
+
+
+⚠️ Caution: this option can lead to security vulnerabilities and unexpected behavior. Use of this option in production is not supported by Apollo.
+
+When set to `true`, disable validation of graphql operations entirely.
+ |
+
+
diff --git a/packages/integration-testsuite/src/apolloServerTests.ts b/packages/integration-testsuite/src/apolloServerTests.ts
index fabfb446492..102db81bb11 100644
--- a/packages/integration-testsuite/src/apolloServerTests.ts
+++ b/packages/integration-testsuite/src/apolloServerTests.ts
@@ -312,6 +312,21 @@ export function defineIntegrationTestSuiteApolloServerTests(
);
});
+ it('allows disabling validation rules', async () => {
+ const uri = await createServerAndGetUrl({
+ schema,
+ stopOnTerminationSignals: false,
+ nodeEnv: 'production',
+ dangerouslyDisableValidation: true,
+ });
+
+ const apolloFetch = createApolloFetch({ uri });
+
+ const result = await apolloFetch({ query: INTROSPECTION_QUERY });
+ expect(result.data).toBeDefined();
+ expect(result.errors).toBeUndefined();
+ });
+
it('allows introspection to be enabled explicitly', async () => {
const uri = await createServerAndGetUrl({
schema,
diff --git a/packages/server/src/ApolloServer.ts b/packages/server/src/ApolloServer.ts
index 3ecf63b46fb..9455652e21f 100644
--- a/packages/server/src/ApolloServer.ts
+++ b/packages/server/src/ApolloServer.ts
@@ -155,7 +155,7 @@ type ServerState =
export interface ApolloServerInternals {
state: ServerState;
gatewayExecutor: GatewayExecutor | null;
-
+ dangerouslyDisableValidation?: boolean;
formatError?: (
formattedError: GraphQLFormattedError,
error: unknown,
@@ -296,6 +296,8 @@ export class ApolloServer {
...(config.validationRules ?? []),
...(introspectionEnabled ? [] : [NoIntrospection]),
],
+ dangerouslyDisableValidation:
+ config.dangerouslyDisableValidation ?? false,
fieldResolver: config.fieldResolver,
includeStacktraceInErrorResponses:
config.includeStacktraceInErrorResponses ??
diff --git a/packages/server/src/externalTypes/constructor.ts b/packages/server/src/externalTypes/constructor.ts
index ffd1cf6f783..04cf0653d82 100644
--- a/packages/server/src/externalTypes/constructor.ts
+++ b/packages/server/src/externalTypes/constructor.ts
@@ -97,6 +97,7 @@ interface ApolloServerOptionsBase {
apollo?: ApolloConfigInput;
nodeEnv?: string;
documentStore?: DocumentStore | null;
+ dangerouslyDisableValidation?: boolean;
csrfPrevention?: CSRFPreventionOptions | boolean;
// Used for parsing operations; unlike in AS3, this is not also used for
diff --git a/packages/server/src/requestPipeline.ts b/packages/server/src/requestPipeline.ts
index 33987974088..b798cc181ab 100644
--- a/packages/server/src/requestPipeline.ts
+++ b/packages/server/src/requestPipeline.ts
@@ -235,27 +235,29 @@ export async function processGraphQLRequest(
}
await parsingDidEnd();
- const validationDidEnd = await invokeDidStartHook(
- requestListeners,
- async (l) =>
- l.validationDidStart?.(
- requestContext as GraphQLRequestContextValidationDidStart,
- ),
- );
-
- const validationErrors = validate(
- schemaDerivedData.schema,
- requestContext.document,
- [...specifiedRules, ...internals.validationRules],
- );
+ if (internals.dangerouslyDisableValidation !== true) {
+ const validationDidEnd = await invokeDidStartHook(
+ requestListeners,
+ async (l) =>
+ l.validationDidStart?.(
+ requestContext as GraphQLRequestContextValidationDidStart,
+ ),
+ );
- if (validationErrors.length === 0) {
- await validationDidEnd();
- } else {
- await validationDidEnd(validationErrors);
- return await sendErrorResponse(
- validationErrors.map((error) => new ValidationError(error)),
+ const validationErrors = validate(
+ schemaDerivedData.schema,
+ requestContext.document,
+ [...specifiedRules, ...internals.validationRules],
);
+
+ if (validationErrors.length === 0) {
+ await validationDidEnd();
+ } else {
+ await validationDidEnd(validationErrors);
+ return await sendErrorResponse(
+ validationErrors.map((error) => new ValidationError(error)),
+ );
+ }
}
if (schemaDerivedData.documentStore) {