NAME
GraphQL::Houtou::PSGI - GraphQL over HTTP endpoint as a plain PSGI app
SYNOPSIS
# app.psgi
use GraphQL::Houtou::PSGI;
use GraphQL::Houtou::DataLoader;
GraphQL::Houtou::PSGI->new(
schema => $schema,
graphiql => 1,
context => sub {
my ($env) = @_;
my $users = GraphQL::Houtou::DataLoader->new(batch => \&batch_users);
my $context = { users => $users, env => $env };
return ($context, GraphQL::Houtou::DataLoader->on_stall_for($users));
},
)->to_app;
DESCRIPTION
A GraphQL over HTTP endpoint built directly on the PSGI interface - no Plack modules are required at runtime. Responses are rendered by the direct-JSON execution lane (execute_document_to_json), so the Perl response envelope is never materialized: sync schemas take the streaming fast lane and batching (DataLoader) schemas take the async lane with the JSON tail.
OPTIONS
- schema / runtime
-
Either a GraphQL::Houtou::Schema (a native runtime is built once at construction) or a prebuilt GraphQL::Houtou::Runtime::NativeRuntime.
- context
-
A hashref passed to resolvers as-is, or a coderef called once per request with the PSGI
$env. The coderef may return the context alone or a($context, $on_stall)pair - the natural shape when per-request DataLoaders live inside the context (see SYNOPSIS). - on_stall
-
A static stall-flush hook (see "Batching resolvers" in GraphQL::Houtou). A per-request hook returned by the
contextbuilder takes precedence. - graphiql
-
Serve the GraphiQL IDE (loaded from the esm.sh CDN) on
GETrequests whoseAcceptincludestext/html.graphiql_pathoverrides the endpoint URL the IDE posts to (defaults to the page's own path). - async
-
Passed to
build_native_runtimewhen the app is constructed from aschema. Declare it when resolvers return promises (DataLoader or other Promise::XS sources) so every request starts on the async-capable lane (see "Declaring an async schema" in GraphQL::Houtou). Requests that carry anon_stallhook run on the async lane either way, so pure DataLoader apps work without it -asyncmatters when promises can appear without a stall-flush hook. - root_value, max_depth, max_nodes, max_cost, default_list_size, program_cache_max
-
Passed through to the runtime.
max_depthcaps query nesting;max_nodescaps the total field selections an operation resolves (alias-flooding defense).max_costcaps weighted field cost;default_list_sizeis the multiplier for list fields without an explicitlist_size(defaults to 10). Limits reject over-limit queries with an errors-only 400 response. - allow_introspection
-
Defaults to true. Set to
0on public endpoints to reject__schemaand__typewith anINTROSPECTION_DISABLEDrequest error.__typenameremains available. Whenschemais supplied the option is also applied to the runtime built by the adapter; with a prebuiltruntimeit is applied to each document request. GraphiQL relies on schema introspection, so do not combinegraphiql => 1with a disabled policy unless trusted requests override it outside this adapter. - max_body_size
-
Maximum request body in bytes (default
1048576, i.e. 1 MiB). Bodies whoseContent-Lengthexceeds this, or that read past it, are rejected with a413before parsing. Pass0to disable the cap.
PROTOCOL
POST with Content-Type: application/json and a {"query": ..., "variables": ..., "operationName": ...} body. The response is application/graphql-response+json when the client accepts it, application/json otherwise. Requests that fail before execution (malformed body, parse or validation errors, unknown operationName) return 400 with an errors-only envelope; field-level errors execute to a 200 response with the errors array populated, as GraphQL over HTTP specifies. GET execution is not implemented; GET serves GraphiQL when enabled and 405 otherwise.
Requests naming an operationName are cached like any other: the program cache keys on the (query, operationName) pair, so clients that always send operationName (Apollo Client and friends) stay on the compiled hot path.