Introducing Obsidian: GraphQL, built for Deno

By Travis Frank

There are two distinct parts to Obsidian: ObsidianRouter, a caching GraphQL router built upon Deno's Oak server framework, and ObsidianWrapper, a React component that functions as a GraphQL client for your application, providing global access to fetching and caching capabilities.

Each of these parts aims to provide a seamless GraphQL implementation in Deno, with a caching layer that adheres to the following core values:

  • Fast ~ Caching with obsidian should be nearly imperceptible — a client or server module should feel no slower with a caching layer
  • Opinionated ~ Caching with obsidian should be structured — structure brings clarity, and clarity brings efficiency
  • Consistent ~ Caching with obsidian should prize consistency — discerning truth should be automatic and transparent

Before we cover Obsidian’s caching strategies, let’s learn how you can utilize Obsidian.

ObsidianRouter constructs a complete GraphQL endpoint for your Oak Deno server with user-defined type definitions and resolvers, and creates a caching layer via a local redis instance. Thanks to Deno’s ES module imports, installation is as simple as importing directly from deno.land. Here is an example of how to set up ObsidianRouter:

As long as we’ve got a running redis instance at the port we’ve specified, we can spin up the server and visit the /graphql endpoint to begin using our GraphQL router in the Playground:

deno run --allow-net --unstable server.tsx

Before we discuss caching, let’s examine Obsidian’s client implementation — ObsidianWrapper.

ObsidianWrapper is a React component that provides global access to Obsidian’s fetching and caching capabilities. Installation in your React app is a breeze — simply wrap your top-level component:

Above, we mentioned that Obsidian is designed for React apps built with server-side rendering. To utilize Obsidian’s caching capabilities in the client, we must send an obsidianSchema with our app, attached to the window object. ObsidianRouter helpfully provides this schema for us, which we can extract and send like so:

For more information about Obsidian and server-side rendering, you can learn more in our documentation.

Once we’ve wrapped our app and sent obsidianSchema, we can make caching queries to our endpoint with the gather method, which we access by invoking the useObsidian custom hook:

Obsidian is more than just a GraphQL router and client — Obsidian offers a headlining normalized caching algorithm to ensure your API stays lean and performant, even as its scope grows. To accomplish this, Obsidian normalizes outgoing responses, and reconstructs responses for incoming queries from the normalized caching layer.