Mojolicious::Plugin::GraphQL - a plugin for adding GraphQL route handlers
my $schema = GraphQL::Schema->from_doc(<<'EOF');
schema {
  query: QueryRoot
}
type QueryRoot {
  helloWorld: String
}
EOF
# for Mojolicious substitute "plugin" with $app->plugin(...
# Mojolicious::Lite (with endpoint under "/graphql")
plugin GraphQL => {
  schema => $schema, root_value => { helloWorld => 'Hello, world!' }
};
# OR, equivalently:
plugin GraphQL => {schema => $schema, handler => sub {
  my ($c, $body, $execute, $subscribe_fn) = @_;
  # returns JSON-able Perl data
  $execute->(
    $schema,
    $body->{query},
    { helloWorld => 'Hello, world!' }, # $root_value
    $c->req->headers,
    $body->{variables},
    $body->{operationName},
    undef, # $field_resolver
    $subscribe_fn ? (undef, $subscribe_fn) : (), # only passed for subs
  );
}};
# OR, with bespoke user-lookup and caching:
plugin GraphQL => {schema => $schema, handler => sub {
  my ($c, $body, $execute, $subscribe_fn) = @_;
  my $user = MyStuff::User->lookup($app->request->headers->header('X-Token'));
  die "Invalid user\n" if !$user; # turned into GraphQL { errors => [ ... ] }
  my $cached_result = MyStuff::RequestCache->lookup($user, $body->{query});
  return $cached_result if $cached_result;
  MyStuff::RequestCache->cache_and_return($execute->(
    $schema,
    $body->{query},
    undef, # $root_value
    $user, # per-request info
    $body->{variables},
    $body->{operationName},
    undef, # $field_resolver
    $subscribe_fn ? (undef, $subscribe_fn) : (), # only passed for subs
  ));
};
# With GraphiQL, on /graphql
plugin GraphQL => {schema => $schema, graphiql => 1};
This plugin allows you to easily define a route handler implementing a
GraphQL endpoint, including a websocket for subscriptions following
Apollo's subscriptions-transport-ws protocol.
As of version 0.09, it will supply the necessary promise_code
parameter to "execute" in GraphQL::Execution. This means your resolvers
can (and indeed should) return Promise objects to function
asynchronously. As of 0.15 these must be "Promises/A+" as subscriptions
require resolve and reject methods.
The route handler code will be compiled to behave like the following:
- Passes to the GraphQL execute, possibly via your supplied handler,
the given schema, 
$root_valueand$field_resolver. Note as above that the wrapper used in this plugin will supply the hash-ref matching "PromiseCode" in GraphQL::Type::Library. - The action built matches POST / GET requests.
 - Returns GraphQL results in JSON form.
 
Mojolicious::Plugin::GraphQL supports the following options.
Array-ref. First element is a classname-part, which will be prepended with
"GraphQL::Plugin::Convert::". The other values will be passed
to that class's "to_graphql" in GraphQL::Plugin::Convert method. The
returned hash-ref will be used to set options, particularly schema,
and probably at least one of resolver and root_value.
String. Defaults to /graphql.
A GraphQL::Schema object. As of 0.15, must be supplied.
An optional root value, passed to top-level resolvers.
An optional field resolver, replacing the GraphQL default.
An optional route-handler, replacing the plugin's default - see example above for possibilities.
It must return JSON-able Perl data in the GraphQL format, which is a hash
with at least one of a data key and/or an errors key.
If it throws an exception, that will be turned into a GraphQL-formatted error.
If being used for a subscription, it will be called with a fourth parameter as shown above. It is safe to not handle this if you are content with GraphQL's defaults.
Boolean controlling whether requesting the endpoint with Accept: text/html will return the GraphiQL user interface. Defaults to false.
# Mojolicious::Lite
plugin GraphQL => {schema => $schema, graphiql => 1};
Defaults to 0, which means do not send. Otherwise will send a keep-alive packet over websocket every specified number of seconds.
Mojolicious::Plugin::GraphQL inherits all methods from Mojolicious::Plugin and implements the following new ones.
my $route = $plugin->register(Mojolicious->new, {schema => $schema});
Register renderer in Mojolicious application.
Exportable is the function promise_code, which returns a hash-ref
suitable for passing as the 8th argument to "execute" in GraphQL::Execution.
To use subscriptions within your web app, just insert this JavaScript:
<script src="https://unpkg.com/%3Ca%20href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0f7c7a6d7c6c7d667f7b6660617c227b7d6e617c7f607d7b22787c4f3f2136213e39">[email protected]/browser/client.js"></script>
# ...
const subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient(websocket_uri, {
  reconnect: true
});
subscriptionsClient.request({
  query: "subscription s($c: [String!]) {subscribe(channels: $c) {channel username dateTime message}}",
  variables: { c: channel },
}).subscribe({
  next(payload) {
    var msg = payload.data.subscribe;
    console.log(msg.username + ' said', msg.message);
  },
  error: console.error,
});
Note the use of parameterised queries, where you only need to change
the variables parameter. The above is adapted from the sample app,
https://github.com/graphql-perl/sample-mojolicious.
https://github.com/apollographql/subscriptions-transport-ws#client-browser - Apollo documentation
Ed J
Based heavily on Mojolicious::Plugin::PODRenderer.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.