How to add custom REST endpoints to your Agent
Introduction
uAgents now support custom REST endpoints using the on_rest_get()
and on_rest_post()
decorators, enabling them to handle HTTP GET and POST requests directly. With this addition, agents can define specific routes, create request and response models, and interact seamlessly with REST clients. This feature enhances the flexibility of agents, allowing them to communicate with external systems using standard web protocols while ensuring that all responses conform to predefined models. Please note that this feature is only available at the ‘agent level’, meaning that you cannot add REST endpoints to uAgents protocols
!
The usage is similar to a message handler in that you define:
- A custom endpoint in string format, e.g.
"/my_rest_endpoint"
; - A Request Model (inheriting from
uagents.models
) forPOST
endpoints; - A Response Model for
GET
endpoints.
The difference to a message handler is that you actually have to invoke return
for the value to be returned to the REST client. The format can either be Dict[str, Any]
or the Model
itself but either way the output will be validated against the predefined response model.
Usage
To use the new REST API feature in your agent, follow these steps to define custom GET
and POST
routes, run the Agent, and query the endpoints.
For querying the Agent you have to make sure that:
- You use the correct REST method (“GET” or “POST”).
- You address the Agent endpoint together with its route e.g
http://localhost:8000/custom_route
.
Define Custom GET and POST Routes
GET request example
Use the @on_rest_get()
decorator to define a custom GET endpoint. You will need to specify the endpoint route and the response model.
@agent.on_rest_get("/custom_get_route", Response)
async def handle_get(ctx: Context) -> Dict[str, Any]:
return {
"field": <value>,
}
POST request example
Use the @on_rest_post()
decorator to define a custom POST endpoint. You need to provide both a request model (for input) and a response model (for output).
@agent.on_rest_post("/custom_post_route", Request, Response)
async def handle_post(ctx: Context, req: Request) -> Response:
ctx.logger.info(req)
return Response(...)
Example of custom GET and POST Routes
import time
from typing import Any, Dict
from uagents import Agent, Context, Model
class Request(Model):
text: str
class Response(Model):
timestamp: int
text: str
agent_address: str
# You can also use empty models to represent empty request/response bodies
class EmptyMessage(Model):
pass
agent = Agent(name="Rest API", seed="your_seed_phrase", port=8000, endpoint=["http://localhost:8000/submit"])
@agent.on_rest_get("/rest/get", Response)
async def handle_get(ctx: Context) -> Dict[str, Any]:
ctx.logger.info("Received GET request")
return {
"timestamp": int(time.time()),
"text": "Hello from the GET handler!",
"agent_address": ctx.agent.address,
}
@agent.on_rest_post("/rest/post", Request, Response)
async def handle_post(ctx: Context, req: Request) -> Response:
ctx.logger.info("Received POST request")
return Response(
text=f"Received: {req.text}",
agent_address=ctx.agent.address,
timestamp=int(time.time()),
)
if __name__ == "__main__":
agent.run()
Run the example
-
Run the agent:
python agent.py
-
Query the agent directly through your predefined interfaces:
curl -d '{"text": "test"}' -H "Content-Type: application/json" -X POST http://localhost:8000/rest/post
Expected output
-
Curl Response:
{"timestamp": 1725610956, "text": "Received: test", "agent_address": "agent1q2qavahvzm2yw237g2cq40pe8p590ppysclaffp2dd0gtk9evtxag7c8djd"}
-
Agent Logs:
WARNING: [Rest API]: No endpoints provided. Skipping registration: Agent won't be reachable. INFO: [Rest API]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit) INFO: [Rest API]: Received POST request