A simple HTTP and gRPC echo server with WebSocket, Server-Sent Events (SSE), and an OpenAPI 3.0 PetStore API.
Note: This project is a fork of the jmalloc/echo-server repository. It adds gRPC support and an OpenAPI 3.0-compliant PetStore API.
- HTTP echo (returns request details)
- gRPC echo service
- WebSocket echo
- Server-Sent Events (SSE)
- OpenAPI 3.0 PetStore API
- Health check endpoint
A simple HTTP and gRPC echo server for testing HTTP proxies and clients. It echoes information about HTTP request headers and bodies. It also supports WebSocket and SSE.
- Messages sent from a WebSocket client are echoed back as WebSocket messages.
- Requests to
*.wsunder any path serve a simple UI for WebSocket testing. - Requests to
*.sseunder any path stream server-sent events. - All other URLs return an HTTP echo response in plain text.
curl -X POST http://localhost:8080 \
-H "Content-Type: application/json" \
-d '{"message": "hello world"}'grpcurl -plaintext -d '{"message": "hello"}' localhost:9090 echo.Echo/Echowscat -c ws://localhost:8080/.ws
# Then type a message and press enter to see it echoed backRequests to any path ending with .sse will stream server-sent events to the client.
curl http://localhost:8080/.sseThe /throw endpoint allows you to simulate HTTP error responses by specifying a status code.
Usage:
curl -i "http://localhost:8080/throw?code=404"Response:
HTTP/1.1 404 Not Found
Content-Type: application/json
{"error":"This is a forced error with status 404"}
- Pass any valid HTTP status code (100-599) as the
codequery parameter. - Invalid or out-of-range codes will return a 400 Bad Request with
{"error":"Invalid status code"}.
Implements a simple PetStore API based on OpenAPI 3.0.
The spec is located at cmd/echo-server/openapi/petstore.yaml.
| Method | Path | Description | Example |
|---|---|---|---|
| GET | /v1/pets |
List all pets (limit optional, max 100) |
curl http://localhost:8080/v1/pets?limit=10 |
| POST | /v1/pets |
Create a new pet (name, tag) |
curl -X POST http://localhost:8080/v1/pets -H 'Content-Type: application/json' -d '{"name":"Joe","tag":"parrot"}' |
| GET | /v1/pets/{petId} |
Retrieve a specific pet | curl http://localhost:8080/v1/pets/1 |
{
"id": 1,
"name": "Fluffy",
"tag": "cat"
}{
"code": 404,
"message": "Pet not found"
}- Thread-safe (mutex locks)
- Preloaded with 2 sample pets
- Validation for required fields
- In-memory only (data lost on restart)
curl http://localhost:8080/health| Variable | Description |
|---|---|
PORT, GRPC_PORT |
Set server ports (default 8080 / 9090) |
LOG_HTTP_HEADERS, LOG_HTTP_BODY |
Enable HTTP request logging |
SEND_SERVER_HOSTNAME |
Include hostname in echo response |
SEND_HEADER_* |
Add custom response headers |
WEBSOCKET_ROOT |
Prefix for WebSocket UI requests |
PORTsets the HTTP server port (default: 8080)GRPC_PORTsets the gRPC server port (default: 9090)
Set environment variables to enable request logging:
LOG_HTTP_HEADERS=true
LOG_HTTP_BODY=trueBy default, the server includes its hostname in responses.
To disable this behavior:
SEND_SERVER_HOSTNAME=falseThe client can also override this per request using the header:
X-Send-Server-Hostname: false
Add arbitrary headers using environment variables prefixed with SEND_HEADER_.
Underscores become hyphens.
Example (to disable CORS restrictions):
SEND_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN="*"
SEND_HEADER_ACCESS_CONTROL_ALLOW_METHODS="*"
SEND_HEADER_ACCESS_CONTROL_ALLOW_HEADERS="*"Set WEBSOCKET_ROOT to prefix all WebSocket requests made from the .ws UI.
Example:
WEBSOCKET_ROOT=/customThen visit:
http://localhost:8080/custom.ws
# Run tests
make test
# Build binary
make build
# Build Docker image
make docker# Run the built binary
PORT=8081 ./artifacts/build/release/linux/amd64/echo-server
# Or run directly with Go
PORT=8081 go run ./cmd/echo-serverdocker run --name echo-server -p 8080:8080 -p 9090:9090 stojs/echo-server:dev