With the release of SurrealDB 3.0, we’re excited to announce the stabilisation of a powerful feature: DEFINE API. This innovative addition allows developers to define database behaviours, set up middleware, and create custom API endpoints directly within the familiar SurrealQL query language.
Traditionally, applications connect to databases through middleware, resulting in a three-layer architecture:
Client → Middleware (API) → Database
With SurrealDB's new DEFINE API, you can simplify your infrastructure significantly:
Client → Database
This streamlined approach not only reduces complexity but also enhances performance and ease of management.
Real-world use case: implementing rate limits for a social app
Consider a scenario: you've built a popular social application that allows users to see recent comments. You want to provide a free API for anonymous users, but you also need to ensure these guest users don't overload your system resources during peak traffic.
Here are some ways how you can achieve this efficiently using SurrealDB's DEFINE API:
Setup: restrict arbitrary queries
To begin, pass in the new --deny-arbitrary-query flag when starting the SurrealDB server.
This prevents certain groups, like guests or record users, from putting their own queries together. We'll add guest here so that any guest users will have to use the API endpoint instead.
You can then connect using Surrealist, or with the following command in a new terminal window:
Defining your API Endpoint
Next, we'll add a DEFINE API statement to define the endpoint. The statement will start with the path /get_latest , and to specify that it can only be used for GET requests, we will include it after the FOR keyword.
Add middleware functions
We can follow this up with some middleware by passing in some of SurrealDB's API functions. We'll use api::timeout to give guest users up to 50 milliseconds of server time.
Define the RETURN data
And then we'll finish up the statement by adding what it actually returns: a SELECT statement for all comment records that have been created over the past ten minutes:
In summary, that gives us a DEFINE API statement that looks like this.
Testing your endpoint
You can test it from SurrealQL itself by first adding a comment or two and then calling the api::invoke function:
Or externally at: /api/:namespace/:database/:endpoint_name. Here's what our defined endpoint will look like with a namespace called test_ns and a database called test_db.
That means that a curl command like the following will be enough to get the latest comments.
The output should look something like this.
But that’s not all. The MIDDLEWARE clause in a DEFINE API statement can take custom middleware as well that you define yourself using a regular DEFINE FUNCTION statement. These functions are automatically populated with the user request and a way to get the current state of the response as you put it together.
There are a lot of examples in the documentation to show how it works, but here’s a simple example to get you started.
With DEFINE API, SurrealDB brings the power of API design directly into the database - no external layers, no additional frameworks. Whether you’re enforcing limits, defining access, or building powerful custom endpoints, this feature helps you simplify your architecture and move faster.
Explore further
Dive deeper into SurrealDB's powerful API management capabilities:
Harness the power of DEFINE API and redefine what's possible with SurrealDB 3.0.
