Hello Exograph!
We are thrilled to announce the launch of Exograph: a new approach to building GraphQL backends. Exograph introduces a declarative language that lets you focus on your domain model and access control rules – you can have a backend up and running in minutes. Powered by a Rust-based runtime, Exograph ensures quick startup, efficient query execution, and minimal memory consumption. Additionally, Exograph provides a range of tools to help you get started quickly and keep pace with your application's evolving needs. Currently in preview, Exograph is available for download on our website as well as from our GitHub repository.
GraphQL has gained popularity as an API building choice due to its ability to allow clients to specify the required data, avoiding both over-fetching and under-fetching. Nevertheless, developing a GraphQL backend can be challenging and time-consuming, demanding substantial expertise in backend development to ensure security and efficiency. This is where Exograph comes in: it simplifies the process of building GraphQL backends by enabling developers to define their domain model and access control rules, without much additional complexity. The result is a highly productive approach to backend development, allowing you to focus on the unique aspects of your application. With Exograph, you can build your backend during a lunch break!
Here's a taste of Exograph. Let's say you want to build a GraphQL API for a todo app. Here is how you get it done with Exograph:
exo new todo-app
cd todo-app
exo yolo
That's it! You now have a GraphQL API with a GraphQL Playground running on http://localhost:9876/graphql waiting for you to explore.
Of course, this is partly because the "exo new" command creates a todo app as the starter code! But if you examine the starter source file, you will see that we could have done the same from scratch in no time.
@postgres
module TodoDatabase {
@access(true)
type Todo {
@pk id: Int = autoIncrement()
title: String
completed: Boolean
}
}
Essentially, this code defines the domain model and access control rules. Exograph uses this information to generate a GraphQL API for efficiently querying and mutating your data. It handles the underlying execution of SQL queries and enforces the access control rules, relieving you of those concerns. However, Exograph goes beyond managing persistent data; it also provides the capability to extend the core functionality by adding new APIs and augmenting existing ones.
The Exograph Way
Let's briefly tour the core ideas in Exograph that make it an excellent choice for your next project's GraphQL backend. For a more comprehensive introduction, please see our documentation.
Easy Domain Modelling
Exograph provides a declarative language that lets you concisely express your backend's domain model. This language draws inspiration from TypeScript and GraphQL IDL, so if you are already familiar with these or a similar language, you will feel right at home. Additionally, the language ensures type safety, providing compile-time errors instead of runtime surprises when there are errors in the code. Since you write Exograph code in just text files, you use Git (or any other version control system) as you would with any other code making it easy to collaborate with your team and track changes.
Let's say you want to build an e-commerce backend where a department may have multiple products. You define the domain model as follows:
@postgres
module EcommerceDatabase {
@access(true)
type Product {
@pk id: Int = autoIncrement()
name: String
description: String
price: Float
published: Boolean
department: Department
}
@access(true)
type Department {
@pk id: Int = autoIncrement()
name: String
products: Set<Product>?
}
}
Now you will get GraphQL APIs to query and mutate your data. For example, you can query all products in a department as follows:
query {
department(id: 1) {
name
products {
name
price
}
}
}
Fine-Grained Access Control
Access control is a fundamental feature of Exograph. When defining an Exograph model, you can specify access control rules alongside each element. This arrangement ensures that the rules are easy to comprehend and review. Moreover, Exograph's access control rules are highly flexible and customizable. They can be based on various factors such as user roles, the user-entity relationship, captcha verification, the time of day, or any other rules using the extensible "context" mechanism.
The earlier definition of e-commerce has a fatal flaw: anyone can query or mutate anything (due to @access(true)
). Let's consider a scenario where you want to ensure that only administrators can add, update, or delete products or departments. Additionally, you want to restrict regular users to accessing only published products. You can express these requirements in Exograph as follows:
context AuthContext {
@jwt role: String
}
@postgres
module EcommerceDatabase {
@access(query=self.published || AuthContext.role=="admin", mutation=AuthContext.role=="admin")
type Product {
... same as before ...
}
@access(query=true, mutation=AuthContext.role=="admin")
type Department {
... same as before ...
}
}
Now non-admin users will get an authorization error if they try to create, update, or delete a product. Similarly, due to the self.published
part of the rule, non-admin users will see only published products; it doesn't matter how they query it: directly or through a department.
Note the context
element. Rather than baking specific forms of authentication into the language, Exograph provides a flexible mechanism to define your context. In this case, we define one that includes the user's role. You can then use this context in your access control rules. Combined with the extensibility offered by Deno modules, you can implement any authorization rules you need without waiting for Exograph to support it.
Extending the Core Functionality
One of the core principles of Exograph is to let developers mold the application to fit their needs. This way, developers can extend the platform rather than wait for us to implement specific functionalities.
Deno Modules
While working with data is often the dominant part of your application, it is not the whole story. You may also need to execute business logic and integrate your backend with other systems. The Deno modules support in Exograph makes this possible. You can write your business logic in TypeScript or JavaScript. In Exograph, you don't need to write separate backend (micro)services (although you can do that if you want). This embedding approach reduces the number of moving parts, simplifying the deployment process and making it easier to maintain your application.
Let's say you want to implement a GraphQL API to announce a product to possible buyers. You can implement it as follows:
@deno("announce.ts")
module ProductAnnouncement {
@access(AuthContext.role=="admin")
mutation announce(productId: Int, @inject exo: Exograph): String
}
const productQuery = `query getProduct($id: Int) { product(id: $id) { name, price } }`
export function announce(productId: number, exo: Exograph): string {
const product = exo.executeQuery(productQuery, {id: productId});
const potentialBuyers = exo.executeQuery(... analytics GraphQL query ...);
sendEmail(potentialBuyers, "New Product", `A new product ${product.name} is available`);
return "Announced";
}
Here, we declare the announce
mutation. In its implementation, which may be in JavaScript or TypeScript, we use the Exo
object to execute queries to get more information and send emails to potential buyers.
Interceptors
Exograph provides a mechanism to intercept main-line operations. The interceptor mechanism helps modularize cross-cutting concerns such as rate-limiting, auditing, logging, and performance monitoring. It also allows augmenting the core functionality. For instance, you can write an interceptor to email the user when they create an account. Additionally, it provides means to implement authorization rules that are not expressible in the declarative language.
Let's say, you want to audit all mutations by logging who executed what mutation and when. You can implement it as follows:
@deno("audit.ts")
module Audit {
@before("mutation *")
interceptor audit(operation: Operation, authContext: AuthContext)
}
export function audit(operation: Operation, authContext: AuthContext) {
log("Audit: ", operation.name(), authContext.id, new Date());
}
Over time, we will provide a library of interceptors for you to use out of the box. But you don't need to wait for that to happen or accept our way of implementing those concerns.
Fast and Efficient
Exograph starts fast (on a typical laptop, between 1-2 milliseconds and on AWS Lambda, around 200 milliseconds for a cold start), executes efficiently (often executing a single SQL query for even complex GraphQL queries or mutations), and uses very little memory (typically less than 64MB). These characteristics make it suitable for a wide range of applications: from small prototypes to large-scale applications and from traditional servers to serverless platforms.
Exograph's performance is partly due to the architecture that uses ahead-of-time build to reduce runtime computations and partly due to the awesomeness of the Rust programming language and the ecosystem around it.
Deployable Anywhere
You can deploy Exograph pretty much anywhere. Since the executable is a single binary, you can run it on your laptop, your data center, or a serverless platform. We also provide tools to create docker images, for example, to deploy to Fly.
Due to fast startup and low memory consumption, Exograph works well on serverless platforms. This helps to scale your application with varying demands. The exo
cli supports creating and deploying your Exograph backend as an AWS Lambda function. We are working on similar tools for other serverless platforms.
Tooling for Every Stage of Development
Exograph includes a full suite of tools to support every stage of the development lifecycle: from initial development, to deployment, to maintenance. You can start with a simple "yolo" mode, where you don't need to worry about setting up the database. This mode is excellent for getting started quickly. Later, you can use the "dev" mode that automatically updates the server when you make changes. When working with databases, Exograph provides tools to create the initial schema, verify consistency between model and database, and run migrations as your code evolves.
Exograph provides a VS Code Extension to provide syntax highlighting, code completion, and error checking. It also includes a declarative way to test your GraphQL API.
This start-to-finish set of tools makes building and maintaining your GraphQL API easy.
Try Exograph Today
Exograph is currently in preview and available for download on our website. You can also find us on GitHub, Discord, and Twitter. This is just the beginning, with a lot more still to come. Please try it out and let us know how we can make it even better for you!