Skip to content

Commit

Permalink
Add dangerouslyDisableValidation option to @apollo/server (#7786)
Browse files Browse the repository at this point in the history
This adds a `dangerouslyDisableValidation` option to `@apollo/server` which will skip
the validation step for graphql operations.
  • Loading branch information
ganemone committed Nov 14, 2023
1 parent 3fb036f commit 869ec98
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 20 deletions.
6 changes: 6 additions & 0 deletions .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.
15 changes: 15 additions & 0 deletions docs/source/api/apollo-server.mdx
Expand Up @@ -492,6 +492,21 @@ Apollo Server v5 will _always_ behave as if this option is `true` (and will igno
</td>
</tr>

<tr>
<td>

##### `dangerouslyDisableValidation`

`Boolean`
</td>
<td>

鈿狅笍 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.
</td>
</tr>

</tbody>
</table>

Expand Down
15 changes: 15 additions & 0 deletions packages/integration-testsuite/src/apolloServerTests.ts
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/ApolloServer.ts
Expand Up @@ -155,7 +155,7 @@ type ServerState =
export interface ApolloServerInternals<TContext extends BaseContext> {
state: ServerState;
gatewayExecutor: GatewayExecutor | null;

dangerouslyDisableValidation?: boolean;
formatError?: (
formattedError: GraphQLFormattedError,
error: unknown,
Expand Down Expand Up @@ -296,6 +296,8 @@ export class ApolloServer<in out TContext extends BaseContext = BaseContext> {
...(config.validationRules ?? []),
...(introspectionEnabled ? [] : [NoIntrospection]),
],
dangerouslyDisableValidation:
config.dangerouslyDisableValidation ?? false,
fieldResolver: config.fieldResolver,
includeStacktraceInErrorResponses:
config.includeStacktraceInErrorResponses ??
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/externalTypes/constructor.ts
Expand Up @@ -97,6 +97,7 @@ interface ApolloServerOptionsBase<TContext extends BaseContext> {
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
Expand Down
40 changes: 21 additions & 19 deletions packages/server/src/requestPipeline.ts
Expand Up @@ -235,27 +235,29 @@ export async function processGraphQLRequest<TContext extends BaseContext>(
}
await parsingDidEnd();

const validationDidEnd = await invokeDidStartHook(
requestListeners,
async (l) =>
l.validationDidStart?.(
requestContext as GraphQLRequestContextValidationDidStart<TContext>,
),
);

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<TContext>,
),
);

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) {
Expand Down

0 comments on commit 869ec98

Please sign in to comment.