Tag: spring

GraphQL-injection with Automaton/DomainQL

Symbol picture: Injection needle with GraphQL-Logo

In this blog post I will try to explain how we organize data loading in Automaton/DomainQL and walk you through the general idea of it and how to adapt it for your own project.

Conceptually it provides an alternative to asynchronous loading / suspense on application startup.

Background

We are working on the relaunch of a German state-level government application. We have been doing paid Open-Source development for clients for quite some time now and are now doing it again for this project as requested by our client.

On the most general level, we use DomainQL to drive our GraphQL.

Symbolic DomainQL Explanation: Database + JOOQ + DomainQL is combined to GraphQL

The current workflow is that we start with a PostgreSQL database from which JOOQ generates Java classes, so called POJOs (Plain Old Java Objects, basically normal/anemic Java classes with getters and setters according to the old Java Bean standard).

Basic injection in DomainQL

DomainQL already contains a comparatively simple GraphQL injection method based on exports with magic names. At point I’m close to considering it deprecated since the new system works so much better now.

At first I expected DomainQL to be our main thing, but along the way it became clear to me that we needed more and we added Automaton as an additional layer. Where DomainQL is still very general, Automaton has a clear and distinct vision and a very opinionated way of getting there.

GraphQL injection in Automaton

Let’s start with the basic idea of our kind of data injection. In a traditional Javascript application, the user loads the initial HTML document which contains very little, it downloads all the Javascript bundles and CSS bundles and other resources and then the JavaScript is executed and let’s say React starts rendering an application.

For which it might need a lot of data which it loads asynchronously which necessitates loading indicators, which prompted solutions like Suspense etc.

Often, this is preferable to having the user wait longer but it introduces a lot of additional latency, even if we can manage to tame the visual artifacts with Suspense.

But wouldn’t it be awesome if the components didn’t have to request the data they need because it is already there? What if the server could provide all the data the components need by knowing what they will request before they do?

Static Code Analysis

When I started wondering about how to do this, I was already using the solution, a small, maybe odd library I had written earlier called babel-plugin-track-usage.

Code is just data and as we do it, we never actually use JavaScript as-is, but always transpile it, compress it etc.

babel-plugin-track-usage uses the Babel AST to detect and track statically analyzable calls within your code base.

At first we used it for i18n.

    [
        "track-usage",
        {
            "sourceRoot" : "src/main/js/",
            "trackedFunctions": {
                "i18n": {
                    "module": "./service/i18n",
                    "fn": "",
                    "varArgs": true
                }
            },
            "debug": false
        }
    ]
Code language: JSON / JSON with Comments (json)

Here we see the plugin configuration for an i18n service. We define that all our sources are under “src/main/js” (we’re using a Maven project layout) and then we define that we want to track the default export of a module “./service/i18n” which accepts variable arguments.

This lets us write expressions like “i18n("Hello {0}", user)” in our code. The function just looks up the first argument in a translation map that contains all the necessary translations because the babel-plugin-track-usage provided the server with all the invocations of our i18n function as long as all arguments are statically analyzable. With the varArgs setting it only considers the first argument and allows non-static analyzable varargs to follow.

In combination with a mini-Webpack-Plugin, babel-plugin-track-usage then exports JSON data for the server to process.

{
    "usages": {
        "./apps/shipping/processes/crud-test/composites/CRUDList": {
            "requires": [
                "@quinscape/automaton-js", 
                "mobx-react-lite"
            ],
            "calls": {
                "i18n": [
                    ["Foo List"], 
                    ["Action"], 
                    ["owner"]
                ]
            }
        },
        ...
    }
}Code language: JavaScript (javascript)

“usages” contains a map of relative module names as keys. The “calls” array contains a map of symbolic call names (Here our “i18n”) with a nested array containing an array per function invocation found.

“requires” contains an array with all modules required by that module. This can be used to follow all import dependencies and find all calls starting with a module as starting point.

After I extended the library a few times to support template literals, ES6 imports and also identifiers, it was ready to drive our data injection too.

Direct GraphQL Query injection

Schematic diagram illustrating the injection process explained below

Our apps in automaton correspond to Webpack entrypoints. Each of them contains a number of processes that make up the application functionality.

For each process there is a MobX class that defines the process scope containing all the data for the process.

Here is how our first version of GraphQL injection looked and still does, although we rarely use it like this

import { observable } from "mobx";
import { query } from "@quinscape/automaton-js"

export default class ExampleScope {
    @observable
    injected = query(
        // language=GraphQL
            `query iQueryFoo($config: QueryConfigInput!)
        {
            iQueryFoo(config: $config)
            {
                # ...
            }
        }`,
        {
            "config": {
                "pageSize": 5,
                "sortFields": ["name"]
            }
        }
    )
}Code language: JavaScript (javascript)

We important the “query” function from our library which is registered tracked. The function takes a simple template literal string with the query and a static JSON block with the default config as second argument.

The naming conventions for our file tell the server which process the statically analyzable query belongs to. We follow all imports etc.

When the user starts the application with one of its processes, the server can look up the query() calls it found and use that to fetch the data from GraphQL service.

This method works very well, even when we inject many queries. We don’t even need to bother to craft GraphQL documents with multiple queries. All injected queries will be executed together using an internal shortcut without using HTTP. (Hurray for GraphQL’s transport neutrality).

At the end we can then embed all the queried data in our initial HTML object as script tag with fantasy type.

Our system then can provide the process with a new instance of the process scope that magically contains all the injected data blocks and the React components involved can start rendering right away.

The main reason we switched to a different method is that we in fact have a lot of queries to execute in some processes which makes the process scope very lengthy

Indirect GraphQL injection

At first I couldn’t quite figure out an elegant solution until I realized that like so often, the solution to the problem is another layer of indirection.

What we did was to reify the query arguments into its own named thing and add a second tracked function.

We split the injection into multiple files.

First we have the query definition which we put into its own file.

./src/queries/Q_Foo.js
import { query } from "@quinscape/automaton-js"

export default query(
    // language=GraphQL
        `query iQueryFoo($config: QueryConfigInput!)
    {
        iQueryFoo(config: $config)
        {
            # ...
        }
    }`,
    {
        "config": {
            "pageSize": 5,
            "sortFields": ["name"]
        }
    }
)
Code language: JavaScript (javascript)

We have a standard folder where all our named query definitions are located (here shortened to ./src/queries/). Each definition is named after the file it is in, here Q_Foo.

Now to inject the current value of Q_Foo we just need to write

./src/processes/example/example.js
import { observable } from "mobx";
import { query, injection } from "@quinscape/automaton-js"
import Q_Foo from "../../queries/Q_Foo"

export default class ExampleScope {
    @observable
    injected = injection(Q_Foo)
}Code language: JavaScript (javascript)

I just love the way it works out. The Javascript syntax is just like one would normally write it, I can use my IDE to ctrl+click on the the name and lookup the definitions (or do quick lookups etc). Everything is neatly organized and the scope definitions are much clearer.

The plugin just generates a special JSON block for our identifier

{
    "usages": {
        "./src/processes/example/example": {
            "requires": [
                "mobx",
                "@quinscape/automaton-js",
                "./src/queries/Q_Foo"
            ],
            "calls": {
                "injection": [
                    [
                        {
                            "__identifier": "Q_Foo"
                        }
                    ]
                ]
            }
        }
    }
}
Code language: JSON / JSON with Comments (json)

The JSON data just provides the name and the server has to know / define what that means, in our case “Hey there should be a ‘./src/queries/Q_Foo’ which in turn contains a query() invocation that defines what data we want here.”

Links

Hood: example application for jcouchdb 0.10.0-1

On the occasion of presenting CouchDB and jcouchdb at my place of work, I got around to finally create a small example application that is now downloadable as sneak preview. There need to be bugs fixed, features implemented and lots of documentation to be added, but it kind of works.

It’s called “Hood” for neighbourhood and allows you to mark places or people around a place of activity of yours, called hood. it is meant to foster collaboration / tips on local places etc.

It’s Spring Web Application demonstrating some techniques of working with jcouchdb. It’s an eclipse WTP/Spring IDE project with all dependencies you need besides couchdb and tomcat or another servlet container.

Stay tuned for hood to grow into a fullblown app.

Links:

Twitter/IRC integration with boticelli

I have been planning to release my IRC bot project as open source for quite a while now and the recently added twitter integration gave me the final push to actually do it. So now I am proud to announce the inital release of boticelli, a java / spring IRC bot/web application based on the martyr IRC library. Its mean to be easily configurable and extendable and ships with lots of plugins already included.

Available Plugins:

  • Logging – log channel conversation and provide a web interface to browse and search them
  • Seen – Remembers when a user last spoke in the channel
  • FAQ – Manages a keyword list of FAQ keywords that are matched to a description. Useful to provide answers for reoccuring topics in the channel.
  • AccountCreator?/Revoke/Grant – commands to automatically create accounts for the webapplication and to revoke / grant web app access rights (for ops)
  • ServerPing? – plugin that detects broken connections and makes the bot reconnect.
  • Say – plugin to let the bot say something or make it do something (a CTCP Action)
  • Twitter – two way integration into twitter over a bot specific twitter account.

So if you’re into old-school IRC fun, head over to google code and grab yourself a copy.

Links:

Hybrid XML-Annotation-based Controllers in Spring

When talking to people about the Spring MVC, it became increasingly clear to me that many are thrilled by the possibilities of using annotation based controllers but are somewhat put off by auto discovery / auto-injecting.

Luckily, it’s pretty easy to combine the power of annotation-based MVC Controller (extremely flexible controller methods, flexible binding and validation) and the advantages of  externally declared beans: You continue to use the @Controller annotation, but you don’t use a <context:component-scan/> directive.

 

Spring Praxishandbuch

I’ve been working a lot with the Spring Framework again in the last year. Apart from lots of my work involving it and the JsServ Interceptor I wrote last weekend, another result of this is a book some people from my company wrote. It is about Spring and integrating other technologies into it. It is meant to focus on the practical aspects and tries to explain some exemplary solutions to common problems encountered when working with Spring.

I wrote an awesome chapter about web development with Spring which contains examples for creating a little shop application with a REST-like interface in Spring Web MVC and Spring Webflow. 

So if you like a read a brilliant book Spring development, go and buy it 🙂. This might work best if you can read German, but you can buy one anyway if you don’t. Hell, buy two and give one away for Xmas.

The book and example code should be available in a few days. 

Links:

JsServ – Serverside Javascript and DOM emulation

I played around with some ideas about JavaScript on the server-side and came up with this little prototype. It’s a set a spring components that allow running the scripts in a website on the server side in case a user has no support for JavaScript or has disabled it.

The following diagram shows the way things work:

The parts of jsserv

The parts of jsserv

The DOMInterceptor intercepts the HTML output of other controller and initializes a dom state with it. The document itself is parsed into a DOM tree and the referenced scripts are loaded and executed. Additional patch scripts can be defined to alter the behaviour of other scripts.

The current version adds
<a class="eventHelper" href="/app/event?uuid=42">...</a>

Links around every element for which a onclick handler is registered. The links point to a DOMEvent Controller that triggers updates in the user’s DOM State.

A little example scripts implements a collapsable tree that changes the style classes of nested unordered lists. With the JsServ DOM Manipulation this works with JavaScript as well as without JavaScript on the client side.

While this code is only a rough sketch it promises a lot in terms of vastly reducing the amount of work for sites that must use javascript to get an optimal user experience but who cannot or want not to have a java-script only site. Although the link-as-click event method is rather limited, it is good enough to make a lot of DOM manipulations possible. Expressed only once in JavaScript. Running in it’s deluxe form for people with client-side JavaScript and in a basic form for people with the help of using server-side JavaScript. All is seamlessly integratable into all kinds of Controllers.

Links:

Dependencies:

Edit: code.google.com link added, update to 0.12

© 2024 fforw.de

Theme by Anders NorénUp ↑