GraphQL is coming to Angel (and Dart)

What could be a "killer feature" for the Angel framework, is coming very soon.

As my close friends will surely tell you, I have a habit of taking on multiple projects at a time, getting so excited to be trying something new, that I leave other projects in the dust. Thus, my previous effort to implement the GraphQL specification in Dart resulted in two projects, graphql_parser and graphql_schema, that sat untouched, collecting dust for two years.

Thanks to a great a piece of advice from my dear friend Mark Thompson, though, I re-committed to focusing on only one project at a time, and that has been all the difference. I’ve spent the past several days working hard to complete an implementation of the GraphQL specification, and now all that is left is adding more unit tests, and documentation before version 1.0.0 can be released to the public!

What is GraphQL?

GraphQL, if you haven’t heard of it yet, is a query language, spearheaded by Facebook, which is used by front-end clients to access backends via a single back-end.

Instead of interacting with multiple URI endpoints, you can send a query like the following:

{  todos {    id    text    completed    changes(type: MODIFY) {        description        timestamp    }  }  foo(bar: "baz") {    id    name  }}

The following packages can be used to implement a GraphQL server in Dart:

  • package:graphql_parser
  • package:graphql_schema
  • package:graphql_server
  • Optionally – package:angel_graphql

All three packages can be found in the mono-repo:

Doesn’t directly depend on Angel

Because GraphQL is an open specification, and because clearly, not every server-side user of Dart is using or interested in Angel, I made sure to include all of the core functionality in packages not tied to Angel in any way. Certainly, there is more boilerplate without it, but that’s simply because the process of integrating the different components will look different based on your individual setup.

Angel has dedicated support for GraphQL

If the same person who built Angel built this specific GraphQL implementation, then it’s only natural that there is an Angel package ready to be used to simplify integration of GraphQL into Angel.

package:angel_graphql will be the first step in upgrading the Angel framework to a new version, 1.2.0, in which changes will be made to make Angel more convenient to use with Flutter, to correct dated design decisions leftover from the early releases, and to make Angel a more attractive target for teams and enterprise users. Its origins were in making smaller projects faster to develop, but over time, Angel has added features applicable to a wide array of applications. A new, cleaner version of the framework will allow users to fully take advantage of what is available.

The example_star_wars directory is a brief example of using GraphQL with Angel. Angel itself was initially modeled after Express, so it’s only fitting that Angel’s support for GraphQL resembles graphql-js, the official reference implementation that can be used within Express:

// Finally, create the schema.  var schema = graphQLSchema(    queryType: queryType,    mutationType: mutationType,  );  // Next, create a GraphQL object, which will be passed to `graphQLHttp`, and  // used to mount a spec-compliant GraphQL endpoint on the server.  var graphQL = new GraphQL(schema);  // Mount the GraphQL endpoint.  app.all('/graphql', graphQLHttp(graphQL));  // In development, we'll want to mount GraphiQL, for easy management of the database.  if (!app.isProduction) {    app.get('/graphiql', graphiQL());  }

General usage

As one might surmise from the above example, the core functionality is contained in a GraphQLSchema instance.

Building one is facilitated by a few helper functions, such as objectType, field, and more:

// Create the query type.//// Use the `resolveViaServiceIndex` helper to load data directly from an// Angel service.var queryType = objectType(    'StarWarsQuery',    description: 'A long time ago, in a galaxy far, far away...',    fields: [      field(        'droids',        listOf(droidType.nonNullable()),        description: 'All droids in the known galaxy.',        resolve: resolveViaServiceIndex(droidService),      ),      field(        'humans',        listOf(humanType.nonNullable()),        description: 'All humans in the known galaxy.',        resolve: resolveViaServiceIndex(humansService),      ),      field(        'starships',        listOf(starshipType.nonNullable()),        description: 'All starships in the known galaxy.',        resolve: resolveViaServiceIndex(starshipService),      ),      field(        'hero',        heroType,        description:            'Finds a random hero within the known galaxy, whether a Droid or Human.',        inputs: [          new GraphQLFieldInput('ep', episodeType),        ],        resolve: randomHeroResolver(droidService, humansService, rnd),      ),    ],);

Similarly to graphql-js, every field on an object type needs a resolve function, which is used to fetch its value when it is requested.

package:angel_graphql provides convenience methods, like resolveViaServiceIndex and resolveViaServiceRead, to resolve fields by calling methods on Angel’s Service API, which can be used to abstract access to a data source, whether it is a database, external API, or something else.

package:graphql_server also contains two top-level functions, convertDartClass and convertDartType, that use dart:mirrors to reflect information from types in the current isolate, and build GraphQL object types without all of the typical boilerplate.

Planned videos and articles

You won’t be left in the dark; I plan to record several videos, and write a few articles to explain the usage of package:graphql_server, as well as adding documentation to the Github repo itself, and Angel-specific documentation in the Angel wiki. Be on the lookout for these titles within the coming weeks:

  • Flutter + GraphQL apps with Angel
  • Star Wars – an example project with Angel + GraphQL
  • A brief introduction to package:graphql_server in Dart
  • And more…

What’s next?

Coming eventually will be an implementation of GraphQL subscriptions in Angel based on package:angel_websocket, as well as functionality layered on top of package:angel_client for client-side access on the Web, and in Flutter.