Zuplo

GraphQL Introspection Filter Policy

Filters GraphQL introspection responses to exclude specific types and fields.

This policy intercepts GraphQL introspection query responses and removes configured types and fields from the schema. Useful for hiding internal types or sensitive fields from the public schema.

Configuration

The configuration shows how to configure the policy in the 'policies.json' document.

JSONCode
{ "name": "my-graphql-introspection-filter-outbound-policy", "policyType": "graphql-introspection-filter-outbound", "handler": { "export": "GraphQLIntrospectionFilterOutboundPolicy", "module": "$import(@zuplo/graphql)", "options": { "excludeTypeFields": { "User": ["password", "email"], "Query": ["adminUsers"] }, "excludeTypes": "UserInternal" } } }

Policy Configuration

  • name <string> - The name of your policy instance. This is used as a reference in your routes.
  • policyType <string> - The identifier of the policy. This is used by the Zuplo UI. Value should be graphql-introspection-filter-outbound.
  • handler.export <string> - The name of the exported type. Value should be GraphQLIntrospectionFilterOutboundPolicy.
  • handler.module <string> - The module containing the policy. Value should be $import(@zuplo/graphql).
  • handler.options <object> - The options for this policy. See Policy Options below.

Policy Options

The options for this policy are specified below. All properties are optional unless specifically marked as required.

  • excludeTypes <string[]> - GraphQL Types to exclude from the schema (exact match).
  • excludeTypeFields <object> - Fields on specific GraphQL Types to exclude.

Using the Policy

This policy filters GraphQL introspection responses to selectively hide types and fields from your schema. It intercepts introspection query responses and removes configured types and fields, allowing you to expose a subset of your GraphQL schema to external clients (like MCP servers or AI agents).

How It Works

The policy processes responses from GraphQL introspection queries, which are typically made by GraphQL clients and development tools to discover your API's schema structure. When an introspection response is detected (containing __schema as a top level key), the policy filters out:

  • Entire types specified in excludeTypes
  • Specific fields on types specified in excludeTypeFields

This allows you to hide internal types, sensitive fields, or admin-only operations from public consumers while keeping them available for internal use.

Policy Configuration

Configure the policy with optional excludeTypes and excludeTypeFields options:

JSONCode
{ "name": "filter-introspection", "policyType": "graphql-introspection-filter-outbound", "handler": { "export": "GraphQLIntrospectionFilterOutboundPolicy", "module": "$import(@zuplo/graphql)", "options": { "excludeTypes": ["UserInternal", "AdminType", "DebugInfo"], "excludeTypeFields": { "User": ["password", "ssn"], "Query": ["adminUsers", "debugInfo"] } } } }

Configuration Options

  • excludeTypes (optional): Array of GraphQL type names to completely remove from the schema. Types must match exactly.

  • excludeTypeFields (optional): Object mapping type names to arrays of field names to remove. Only specified fields on the given types will be filtered.

Usage Examples

Hiding Internal Types

Remove internal implementation types from the public schema:

JSONCode
{ "name": "hide-internal-types", "policyType": "graphql-introspection-filter-outbound", "handler": { "export": "GraphQLIntrospectionFilterOutboundPolicy", "module": "$import(@zuplo/graphql)", "options": { "excludeTypes": ["InternalMetadata", "DebugInfo", "SystemStatus"] } } }

Filtering Sensitive Fields

Hide sensitive fields like passwords and admin operations:

JSONCode
{ "name": "filter-sensitive-fields", "policyType": "graphql-introspection-filter-outbound", "handler": { "export": "GraphQLIntrospectionFilterOutboundPolicy", "module": "$import(@zuplo/graphql)", "options": { "excludeTypeFields": { "User": ["password", "ssn", "creditCard"], "Query": ["adminUsers", "systemDiagnostics"], "Mutation": ["deleteAllUsers", "resetDatabase"] } } } }

Complete Example with URL Rewrite

Apply filtering on a route that forwards to a GraphQL endpoint:

JSONCode
{ "paths": { "/graphql": { "x-zuplo-path": { "pathMode": "open-api" }, "post": { "summary": "GraphQL API", "x-zuplo-route": { "corsPolicy": "anything-goes", "handler": { "export": "urlRewriteHandler", "module": "$import(@zuplo/runtime)", "options": { "rewritePattern": "https://api.example.com/graphql" } }, "policies": { "outbound": ["filter-introspection"] } }, "responses": {} } } } }

Important Notes

  • This policy only filters introspection responses - it does not enforce authorization on the actual GraphQL operations. You must still implement proper authorization in your GraphQL resolvers.
  • If a client tries to query a filtered field or type directly, that will be handled by your GraphQL server's validation, not by this policy.
  • The policy only processes successful (200 OK) JSON responses that contain __schema in the response body.
  • If the response cannot be parsed as JSON or is not an introspection response, the original response is returned unchanged.
  • Non-introspection GraphQL queries and mutations pass through without modification.

Security Considerations

  • Filtering introspection is a form of security through obscurity - always implement proper authentication and authorization at the resolver level
  • Consider combining this policy with authentication policies to control who can access your GraphQL endpoint
  • Use this policy to reduce information disclosure about your API's internal structure, but don't rely on it as your only security measure
  • Keep in mind that determined attackers may still discover hidden fields through other means

Read more about how policies work

Last modified on