Introspection
Introspection is what enables GraphQL's rich tooling ecosystem and powerful IDEs like Nitro or GraphiQL.
Every GraphQL server exposes a __schema and __type field on the query type as well as a __typename field on each type. These fields provide insights into the schema of your GraphQL server.
Using the __schema field, you could list the names of all types your GraphQL server contains:
{ __schema { types { name } }}
You could also request the fields plus their arguments of a specific type using the __type field:
{ __type(name: "Book") { fields { name args { name type { name } } } }}
The __typename field is the introspection feature you will use the most in day-to-day development. When working with unions, for example, it tells you the name of the type being returned, letting you handle the result accordingly.
{ posts { __typename ... on VideoPost { videoUrl } ... on TextPost { text } }}
While these fields can be useful to you directly, they are mainly intended for developer tooling. You are unlikely to write your own introspection queries on a daily basis.
Learn more about introspection
Disabling Introspection
While introspection is a powerful feature that can improve your development workflow, it can also be used as an attack vector. Recursive introspection queries (e.g., deeply nested __Type.ofType or __Type.fields chains) can consume significant server resources.
Note that disabling introspection is not about hiding your schema. When using MapGraphQL, the schema is available as a static file at /graphql/schema.graphql. This file is computed once and has no performance impact. The purpose of disabling introspection is to prevent expensive recursive queries against production systems.
Disable introspection by calling AllowIntrospection() with a false argument on the IRequestExecutorBuilder:
builder .AddGraphQL() .AllowIntrospection(false);
While clients can still issue introspection queries, Hot Chocolate returns an error response.
You most likely do not want to disable introspection while developing, so you can toggle it based on the current hosting environment:
builder .AddGraphQL() .AllowIntrospection(builder.Environment.IsDevelopment());
Allowlisting Requests
You can allow introspection on a per-request basis while keeping it disabled for the majority of requests. Create a request interceptor and determine based on the request (the HttpContext) whether to allow introspection.
public class IntrospectionInterceptor : DefaultHttpRequestInterceptor{ public override ValueTask OnCreateAsync(HttpContext context, IRequestExecutor requestExecutor, OperationRequestBuilder requestBuilder, CancellationToken cancellationToken) { if (context.Request.Headers.ContainsKey("X-Allow-Introspection")) { requestBuilder.AllowIntrospection(); }
return base.OnCreateAsync(context, requestExecutor, requestBuilder, cancellationToken); }}
builder .AddGraphQL() // Disable introspection by default .AllowIntrospection(false) .AddHttpRequestInterceptor<IntrospectionInterceptor>();
Custom Error Message
If a client tries to execute an introspection query when introspection is not allowed, they receive an error message similar to the following:
{ "errors": [ { "message": "Introspection is not allowed for the current request.", "locations": [ { "line": 2, "column": 3 } ], "extensions": { "field": "__schema", "code": "HC0046" } } ]}
If you need to customize the error message, do so in your request interceptor:
public class IntrospectionInterceptor : DefaultHttpRequestInterceptor{ public override ValueTask OnCreateAsync(HttpContext context, IRequestExecutor requestExecutor, OperationRequestBuilder requestBuilder, CancellationToken cancellationToken) { if (context.Request.Headers.ContainsKey("X-Allow-Introspection")) { requestBuilder.AllowIntrospection(); } else { // the header is not present, introspection continues // to be disallowed requestBuilder.SetIntrospectionNotAllowedMessage( "Missing `X-Allow-Introspection` header"); }
return base.OnCreateAsync(context, requestExecutor, requestBuilder, cancellationToken); }}
Next Steps
- Interceptors for per-request customization.
- Security for a broader look at securing your GraphQL server.
- Endpoints for configuring the Nitro IDE.