Wilcox Development Solutions Blog

GraphQL in Smalltalk

October 06, 2022

These days most of my analysis - or even short scripts! - start in GToolkit. GToolkit’s paradigm of executable notebooks - with human viewable results - means I can write a script, do my business logic, and not focus on display formatting (much).

Awesome!

As part of my weekly bujo review I want to list all the PRs I’ve closed, on Github, in the last week or so. Now, with the Github GraphQL API I can put that query together with a dozen lines of declarative GraphQL

query {
  viewer {
    pullRequests(first: 24, states: MERGED, orderBy: {field: UPDATED_AT, direction: DESC}) {
      nodes {
        repository {
          nameWithOwner
        }
        closedAt
        url
        title
      }
    }
  }
}

For my user, gives me all my pull requests that are merged, and for each node give me repository name, when I closed it, URL and title.

Super coool. I could run it in Postman… but if I ran it from GToolkit I’d get a bunch of stuff for free, as mentioned. Except there’s no Smalltalk library for GraphQL. So I wrote my own, the graphqlclient-smalltalk.

It’s a very simple GraphQL client for Smalltalk, and missing a lot of things you’ll find in real GraphQL clients. (If you need these things, pull requests welcome…)

Let’s see it in action (both the code and the resulting objects!)

showing this code in the GToolkit editor

The GraphQL client has the following important methods:

  • graphqlEndpoint: <— URL to send all this stuff to
  • operationBody: <— what is your GraphQL query/mutation
  • operationVariables: <— GraphQL variables
  • executeQuery <— do it

Now, how do I get my data out?

executeQuery returns an OperationResult result object, with two helper functions: data and errors.

You could use this object directly, like so


	| q res output |
	q := GraphQLClient new.
	q znclient setBearerAuthentication: KindaSecret githubAuth.

	q graphqlEndpoint: 'https://api.github.com/graphql'.
	q operationBody: 'query {
	  viewer {
	       login
	  }
	}
	'.

	res := q executeQuery.
	res data.

Maybe your GraphQL result is very complicated, and you want to put some clever object traversal or abstraction around it? Great! Create a subclass of OperationResult and define helper methods!

  | q res customOutput |
  "... not going to recopy all that boilerplate..."

  res := q executeQuery.

  customOutput := MyOperationResultSubclassIDefined newFromOperationResult: res.
  customOutput displayMyName.  "<-- a custom method I declared! Look Ma, abstraction!"

OperationResult defines a few helpers for working with query results, and also defines a standard factory function method for subclasses, newFromOperationResult. No matter what the subclass, it can be constructed using this method!

Conclusion

During the creation of this module I really came to appreciate the flexibility of the built-in Smalltalk string literal. Multiline strings just worked right out of the box, I didn’t have to do anything weird. Smalltalk quickly let me iterate on this basic chunk of work, and get something very basic working quickly!

Additionally, during the initial task - get me all that data from Github - I really appreciated the power of GraphQL. In a REST API that would have been multiple query calls manually stiched together - something I experienced just after this when I sarted playing with the Github notifications REST api.


Written by Ryan Wilcox Chief Developer, Wilcox Development Solutions... and other things