Version 0.16 of GraphQL implements most of using the Schema Definition Language to create schemas, rather than doing so programmatically. So let's now translate all the idioms in the JavaScript GraphQL tutorial into Perl!

EDIT version 0.17 implements the rest, so this tutorial translated has been updated slightly as you don't need to specify a schema at all if you call your query type Query , etc.

The format I'll use is to give each of the JS tutorial pages, with the Perl code to do what's given there:

You will need Perl 5.14. Consider using perlbrew to get this.

cpanm Mojolicious::Plugin::GraphQL # also gets Mojolicious and GraphQL

Then the first script:

use 5.014; use GraphQL::Schema; use GraphQL::Execution 'execute'; use Data::Dumper; my $schema = GraphQL::Schema->from_doc(<"Hello world!" });

We'll use Mojolicious::Lite. There's a sample applet on https://github.com/graphql-perl/sample-mojolicious.

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(< { schema => $schema, root_value => { helloWorld => 'Hello, world!' }, graphiql => 1, }; app->start;

Execute with:

./myapp.pl daemon -l http://*:5000

Look at: http://localhost:5000/graphql.

(Note differences are only for ports and field name)

curl -X POST -H "Content-Type: application/json" \ -d '{"query": "{ helloWorld }"}' \ http://localhost:5000/graphql

JavaScript:

var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.open("POST", "/graphql"); xhr.setRequestHeader("Content-Type", "application/json"); xhr.setRequestHeader("Accept", "application/json"); xhr.onload = function () { console.log('data returned:', xhr.response); } xhr.send(JSON.stringify({query: "{ helloWorld }"}));

Note that (I believe) since the tutorial was written, GraphiQL now has a "variables" pane so you can use it for that. The JS console snippet will also work.

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(< sub {rand() < 0.5 ? 'Take it easy' : 'Salvation lies within'}, random => sub {rand()}, rollThreeDice => sub {[map 1+int(rand()*6), (1..3)]}, }; plugin GraphQL => { schema => $schema, root_value => $root_value, graphiql => 1, }; app->start;

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(< sub { my $args = shift; [map 1+int(rand()*$args->{numSides}), (1..$args->{numDice})]}, }; plugin GraphQL => { schema => $schema, root_value => $root_value, graphiql => 1, }; app->start;

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(<$sides}, $class; } sub numSides { shift->{numSides} } sub rollOnce { my ($self) = @_; 1 + int(rand() * $self->{numSides}) } sub roll { my ($self, $args) = @_; [map $self->rollOnce, (1..$args->{numRolls})] } } my $root_value = { getDie => sub { my $args = shift; RandomDie->new($args->{numSides}) }, }; plugin GraphQL => { schema => $schema, root_value => $root_value, graphiql => 1, }; app->start;

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(< $id, %{$args->{input}}}, $class; } sub id { shift->{id} } sub content { shift->{content} } sub author { shift->{author} } } my $fakedb = {}; my $root_value = { getMessage => sub { my $id = shift->{id}; die "No message $id

" if !$fakedb->{$id}; Message->new($id, $fakedb->{$id}) }, createMessage => sub { my $input = shift; # Create a random id for our "database". my $id = int 1000 * rand(); $fakedb->{$id} = {%$input}; Message->new($id, $input) }, updateMessage => sub { my $args = shift; my ($id, $input) = @{$args}{qw(id input)}; die "No message $id

" if !$fakedb->{$id}; # This replaces all old data, but some apps might want partial update. $fakedb->{$id} = {%$input}; Message->new($id, $input) }, }; plugin GraphQL => { schema => $schema, root_value => $root_value, graphiql => 1, }; app->start;

This is a large topic. In order to stay with the non-blocking Mojo idiom, you should use Mojolicious-compatible means of authentication. One method is using under , as discussed here. There is also a Mojolicious plugin to make this easier.

Additionally, the Mojolicious GraphQL plugin will by default pass the request headers on as the "context" (per-request) object to GraphQL::Execution::execute, but with a route-handler you can do anything you like. The plugin's SYNOPSIS gives an example.

Using Schema language:

use Mojolicious::Lite; use GraphQL::Schema; my $schema = GraphQL::Schema->from_doc(< { id => 'a', name => 'alice' }, b => { id => 'b', name => 'bob' }, }; my $root_value = { user => sub { my $id = shift->{id}; die "No user $id

" if !$fakedb->{$id}; $fakedb->{$id} }, }; plugin GraphQL => { schema => $schema, root_value => $root_value, graphiql => 1, }; app->start;

Without Schema language, i.e. instead using resolvers on fields:

use strict; use warnings; use Mojolicious::Lite; use GraphQL::Schema; use GraphQL::Type::Object; use GraphQL::Type::Scalar qw($String); # Maps id to User hashref my $fakedb = { a => { id => 'a', name => 'alice' }, b => { id => 'b', name => 'bob' }, }; my $UserType = GraphQL::Type::Object->new( name => 'User', fields => { id => { type => $String }, name => { type => $String }, }, ); my $schema = GraphQL::Schema->new(query => GraphQL::Type::Object->new( name => 'Query', fields => { user => { type => $UserType, args => { id => { type => $String } }, resolve => sub { my ($root_value, $args) = @_; my $id = $args->{id}; die "No user $id

" if !$fakedb->{$id}; $fakedb->{$id} }, }, }, )); plugin GraphQL => { schema => $schema, graphiql => 1, }; app->start;

For more about resolvers in graphql-perl: graphql-perl resolver documentation.

For more on this, see the Mojolicious::Plugin::GraphQL documentation.

Acknowledgements

The porting of GraphQL to Perl 5 is sponsored by Perl Careers.

Thanks to the folks on #mojo on irc.perl.org for valuable pointers on improving this posting.