wundergraph

High Performance

Everybody would claim to build a highly performant tool. Let's discuss how WunderGraph stands out in terms of performance.

How GraphQL Servers work

To set some context let's first go through the steps a GraphQL server needs to do in order to process a GraphQL request:

  1. accepts the request
  2. reads the request body
  3. parse the request JSON
  4. extract the Query from the JSON
  5. lexing
  6. parsing
  7. normalization
  8. validation
  9. execution
  10. build the JSON response
  11. send response to client

There might be some variations of this, e.g. when using persisted Queries:

  1. accepts the request
  2. extract Query key from hashmap
  3. get Query from hashmap
  4. lexing
  5. parsing
  6. normalization
  7. validation
  8. execution
  9. build the JSON response
  10. send response to client

As you see, even though most implementations could persist Queries they would still run though most of the steps. This has to do with the architecture of these implementations. They act like interpreters who read the input and directly execute it without any intermediate steps that would allow caching or other optimizations.

Compiled Queries

WunderGraph does all this differently to achieve higher levels of security and performance. Instead of simply storing the content of a Query, WunderGraph compiles the Query to an executable tree to reduce the required steps at runtime.

To make this possible WunderGraph distinguishes the two stages, preparation and execution.

The preparation phase

The preparation phase gets initiated by a developer working in the WunderGraph console. Once they persist a new Query it gets propagated to the configured WunderNode which starts the preparation.

During the preparation phase the WunderNode does the following steps:

  1. Before saving the Query it gets validated by the GraphQL.JS reference implementation
  2. propagation to the WunderNode
  3. lexing
  4. parsing
  5. normalization
  6. validation
  7. hashing
  8. planning/Query compilation
  9. storage of the compiled Query in a hashmap

Because all these steps happen at the preparation phase there's a lot less work to be done at runtime.

The execution phase

  1. extract Query ID from request
  2. get compiled Query from hashmap
  3. execute compiled Query
  4. send response to client

As you can see, during the execution phase the WunderNode only does a fraction of the work compared to a regular GraphQL server. But there's more to it.

Builtin DataLoader

With the WunderGraph engine's two-phase approach, its possible to detect if two inflight Queries require the same data.

In that particular scenario WunderGraph groups all requests together who need the same data and only makes one upstream request for all of them. This increases the performance of your existing GraphQL server without changing anything.