Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
Yogananda
Product and Topic Expert
Product and Topic Expert
1,147

Microservices encourage us to build distributed systems consisting of small, specialized components that communicate seamlessly. In this post, let’s explore a simple yet illustrative example: Agent-A and Agent-B, two FastAPI-based Python microservices that interact in real-time.

We'll see how Agent-A receives a request, calls Agent-B, and returns a transformed response—demonstrating the foundations of service-to-service HTTP communication.

The Objective

We want to create:

  • Agent-B: A service that reverses text.
  • Agent-A: A service that takes a string, sends it to Agent-B for reversal, and returns the reversed string as a response.

Both services are built with FastAPI and use Pydantic for data validation.2025-08-02_10-23-41.png

Meet Agent-B: The Reverse Service

Let's begin by looking at agent_b.py. It’s a minimal service that exposes one endpoint that takes a string and returns it reversed.

from fastapi import FastAPI
from pydantic import BaseModel
import os

PORT = int(os.getenv("AGENT_B_PORT", 8001))
app = FastAPI(title="Agent-B")

class ReverseRequest(BaseModel):
    text: str

class ReverseResponse(BaseModel):
    source: str
    reversed: str

@app.post("/reverse", response_model=ReverseResponse)
def reverse(req: ReverseRequest):
    return ReverseResponse(source="Agent-B", reversed=req.text[::-1])

Meet Agent-A: The Forwarding Echo Service

Now, let’s look at agent_a.py. While it’s called an "echo" service, it doesn’t simply echo back input. Instead, it forwards the input to Agent-B, receives the reversed string, and returns that. This demonstrates microservice orchestration.

agent_a.py

from fastapi import FastAPI
from pydantic import BaseModel
import httpx
import os

PORT = int(os.getenv("AGENT_A_PORT", 8000))
B_URL = os.getenv("AGENT_B_URL", "http://localhost:8001")
app = FastAPI(title="Agent-A")

class EchoRequest(BaseModel):
    text: str

class EchoResponse(BaseModel):
    source: str
    echoed: str

@app.post("/echo", response_model=EchoResponse)
async def echo(req: EchoRequest):
    # Forward the text to Agent-B
    async with httpx.AsyncClient() as client:
        r = await client.post(f"{B_URL}/reverse", json={"text": req.text})
        r.raise_for_status()
        reversed_text = r.json()["reversed"]
    # Respond with what Agent-B returned
    return EchoResponse(source="Agent-A", echoed=reversed_text)

 


Running Both Agents

  1. Start Agent-B:

    uvicorn agent_b:app --port 8001
  2. Start Agent-A:

    uvicorn agent_a:app --port 8000

     

Testing the System

Let’s see the microservices in action with curl:

curl -X POST http://localhost:8000/echo \
     -H "Content-Type: application/json" \
     -d '{"text":"hello A2A"}'

Response:

{
  "source": "Agent-A",
  "echoed": "A2A olleh"
}

What happened?

  • The request hits Agent-A’s /echo.
  • Agent-A calls Agent-B’s /reverse with the payload.
  • Agent-B reverses the string.
  • Agent-A returns Agent-B’s output* as its own "echoed" field.

How to Extend This Example

  • Add Logging/Tracing: See the flow end-to-end.
  • Synchronous vs Asynchronous calls: Both are possible; here httpx with async enables efficient concurrency.
  • Error Handling: Add more robust logic in production.
  • Authentication: Secure the endpoints as needed.
  • More Agents: Build a family of collaborating services!

Conclusion

With just a few lines of Python and FastAPI, we built two collaborating microservices with clear responsibilities and simple interaction via HTTP. This pattern underpins many real-world distributed architectures, making it a great learning foundation for building maintainable and scalable systems.

Try extending these agents on your own use case!