Custom API Endpoints: streamlining your architecture
Source: Dev.to

[](https://dev.to/surrealdb)

# Custom API Endpoints: streamlining your architecture
With the release of **SurrealDB 3.0**, we’re excited to announce the stabilisation of a powerful feature: [`DEFINE API`](https://surrealdb.com/docs/surrealql/statements/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.
Below is a step‑by‑step guide to achieving this efficiently using SurrealDB’s `DEFINE API`.
### 1. Setup – restrict arbitrary queries
Start the SurrealDB server with the `--deny‑arbitrary‑query` flag (and enable the experimental `define_api` feature):
```bash
surreal start \
--user root \
--pass root \
--deny-arbitrary-query guest \
--allow-experimental define_api
This prevents certain groups (e.g.,
guestorrecordusers) from sending arbitrary queries. Guest users will have to use the API endpoint instead.
You can then connect with Surrealist or via the CLI:
surreal sql --user root --pass root
2. Define your API endpoint
Add a DEFINE API statement. The endpoint will be reachable at /get_latest and will only accept GET requests:
DEFINE API OVERWRITE "/get_latest" FOR get
3. Add middleware functions
Attach middleware using SurrealDB’s built‑in API functions. Here we give guest users up to 50 ms of server time:
MIDDLEWARE
api::timeout(50ms)
4. Define the return data
Finish the statement by specifying what should be returned – a SELECT of all comment records created in the last ten minutes, ordered by newest first:
THEN {
{
body: SELECT * FROM comment:[time::now()-10m].. ORDER BY id DESC
}
};
5. Full DEFINE API statement
Putting it all together:
DEFINE API OVERWRITE "/get_latest" FOR get
MIDDLEWARE
api::timeout(50ms),
THEN {
{
body: SELECT * FROM comment:[time::now()-10m].. ORDER BY id DESC
}
};
6. Testing your endpoint
From SurrealQL
Create a couple of comments and invoke the endpoint:
CREATE comment:[time::now()] SET user_says = "Nice blog!";
CREATE comment:[time::now()] SET user_says = "Can't wait for the new version";
api::invoke("/get_latest");
Via HTTP
The endpoint is exposed at:
http://localhost:8000/api///get_latest
For a namespace test_ns and a database test_db:
curl -H "Accept: application/json" \
http://localhost:8000/api/test_ns/test_db/get_latest
Expected output
[
{"id":"comment:[d'2026-02-12T01:10:02.445607Z']","user_says":"Can't wait for the new version"},
{"id":"comment:[d'2026-02-12T01:08:33.709073Z']","user_says":"Nice blog!"}
]
Extending middleware
The MIDDLEWARE clause can also accept custom middleware defined with a regular DEFINE FUNCTION statement. These functions automatically receive the user request and can inspect or modify the response as it is built.
For more examples and advanced usage, refer to the official documentation.
Custom API with Arguments
SurrealDB lets you define custom API endpoints directly in the database, allowing you to add middleware and manipulate responses on‑the‑fly. Below is a concise example that demonstrates how to create an API endpoint with a middleware function that adds a prefix to the response body.
DEFINE FUNCTION fn::add_prefix($req: object, $next: function, $prefix: string) -> object {
LET $res = $next($req);
LET $res = $res + {
body: $res.body + {
prefix: $prefix + ": " + $res.body.message
}
};
$res;
};
DEFINE API "/custom_with_args"
FOR get
MIDDLEWARE
fn::add_prefix("PREFIX")
THEN {
{
status: 200,
body: {
message: "original message"
}
};
};
Note: 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.