graphql-perl - plugin to make GraphQL "just work" with Mojo publish/subscribe functionality

GraphQL is the new, shiny way to do APIs. It minimises number of round-trips for clients to query what need. But what about real-time updates? How can we cut down the time needed for clients to get new information? Are we forcing them to constantly poll? That seems expensive and also slow.

GraphQL's official standard now includes "subscriptions". The obvious transport for that is WebSockets, and the de facto standard for that is Apollo GraphQL's subscriptions-transport-ws.

As of 0.16, Mojolicious::Plugin::GraphQL supports WebSockets, and GraphQL subscriptions, conforming to the Apollo protocol.

A well-known model for distributing information in an event-driven way is "publish/subscribe" (or "pub/sub"). To both demonstrate the subscription capability, and to provide useful functionality, there is now a new "convert plugin" for GraphQL with the two Mojo modules that implement pub/sub (with Redis and PostgreSQL): GraphQL::Plugin::Convert::MojoPubSub.

use GraphQL::Plugin::Convert::MojoPubSub;
use GraphQL::Type::Scalar qw($String);
my $pg = Mojo::Pg->new('postgresql://postgres@/test');
my $converted = GraphQL::Plugin::Convert::MojoPubSub->to_graphql(
  {
    username => $String->non_null,
    message => $String->non_null,
  },
  $pg,
);
print $converted->{schema}->to_doc;

Makes this schema:

scalar DateTime
 
input MessageInput {
  channel: String!
  username: String!
  message: String!
}
 
type Message {
  channel: String!
  username: String!
  message: String!
  dateTime: DateTime!
}
 
type Query {
  status: Boolean!
}
 
type Mutation {
  publish(input: [MessageInput!]!): DateTime!
}
 
type Subscription {
  subscribe(channels: [String!]): Message!
}

This is all bundled up for you in https://github.com/graphql-perl/sample-mojolicious which you can install locally by following the README instructions there. You need to install the deps, and have access to a Redis service. If you don’t set an environment variable TEST_REDIS, it defaults to one running on localhost. Then you can have two GraphiQL tabs open, one subscribing to a feed (or everything, the default), and one you can use to create events with a “mutation”. Those will then be reflected in the subscribing tab.

The example here is set up for a chat system, but the module is flexible enough to cover any publish/subscribe scenario (newsfeeds, email messages, etc), just by specifying the right scalar components for messages.

On the technical side, you can “federate” this schema with others to compose together the microservices into a coherent whole. graphql-perl does not yet have a “federate” functionality, but it will - pull requests welcome if you want to contribute!

Your system could create notifications not just by calling the mutation, but by other means. So if using Pg, you could have updates on a table with a trigger to “notify” so subscribers see. If you’re using another database, you could use Redis for notifications by publishing to it in another resolver.

Will you use this? If not, why not (or why not yet)? Please comment, or open an issue on https://github.com/graphql-perl/GraphQL-Plugin-Convert-MojoPubSub/issues!

3 Comments

Awesome to see Perl/Mojo GraphQL libraries! Thank you! If I just want to use Pg can I stop there, or is Redis a requirement along side Pg?

This is impressive!

I have just used it for a little internal project; I didn't realise it was so fresh though.

Could I suggest a followup where you discuss how to amend the schema?

For example:

- if I flat out do not want any of the mutations just for safety reasons
- if I want to add a query type?
- if I want to add a default where clause to an existing query?

I've bodged the first two of these things but I'm sure not healthily...

Oops, I left my comment on the wrong one of your posts. Still -- thanks for the Mojo/GraphQL stuff!

Leave a comment

About Mohawk

user-pic I blog about Perl.