Skip to content
Docs Try Aspire
Docs Try

Go API with In-Memory Storage

Aspire sample
TypeScript AppHost

Clone, run, and explore this sample

REST API built with Go and chi router, using in-memory storage with thread-safe operations.

DockerGoHealth ChecksTypeScript
AppHost

The entry point that composes every resource and dependency in this sample's distributed application.

View on GitHub
apphost.mts
import { createBuilder } from "./.aspire/modules/aspire.mjs";
const builder = await createBuilder();
const executionContext = await builder.executionContext();
await builder.addDockerComposeEnvironment("env")
.configureDashboard(async (dashboard) =>
{
await dashboard.withHostPort({ port: 9003 });
});
if (await executionContext.isPublishMode())
{
await builder.addDockerfile("api", "./api")
.withHttpEndpoint({ env: "PORT" })
.withHttpHealthCheck({ path: "/health" })
.withExternalHttpEndpoints();
}
else
{
const api = await builder.addExecutable("api", "go", "./api", ["run", "main.go"])
.withHttpEndpoint({ env: "PORT" })
.withHttpHealthCheck({ path: "/health" })
.withExternalHttpEndpoints();
const goModInstaller = await builder.addExecutable("api-go-mod-installer", "go", "./api", ["mod", "tidy"])
.withParentRelationship(api);
await api.waitForCompletion(goModInstaller);
}
await builder.build().run();

This sample demonstrates a TypeScript AppHost that runs the Go API directly during local development and switches to a checked-in Dockerfile for Docker Compose publishing.

flowchart LR
    Browser --> API[Go API<br/>chi router]
    API --> Store[In-Memory Store<br/>sync.RWMutex]
  • addExecutable: Runs go mod tidy and go run main.go during local development
  • addDockerfile: Builds a production container image from api/Dockerfile
  • withHttpEndpoint: HTTP endpoint with PORT environment variable
  • withHttpHealthCheck: Health check endpoint at /health
  • In-Memory Storage: Thread-safe CRUD operations with sync.RWMutex
  • Chi Router: Lightweight, idiomatic HTTP router for Go
Terminal window
aspire run
Terminal window
aspire run # Run locally
aspire deploy # Deploy to Docker Compose
aspire do docker-compose-down-dc # Teardown deployment

Go Application - Run with go locally, publish with a Dockerfile:

const executionContext = await builder.executionContext.get();
if (await executionContext.isPublishMode.get())
{
await builder.addDockerfile("api", "./api")
.withHttpEndpoint({ env: "PORT" })
.withHttpHealthCheck({ path: "/health" })
.withExternalHttpEndpoints();
}
else
{
const api = await builder.addExecutable("api", "go", "./api", ["run", "main.go"])
.withHttpEndpoint({ env: "PORT" })
.withHttpHealthCheck({ path: "/health" })
.withExternalHttpEndpoints();
const goModInstaller = await builder.addExecutable("api-go-mod-installer", "go", "./api", ["mod", "tidy"])
.withParentRelationship(api);
await api.waitForCompletion(goModInstaller);
}

Environment Variables - Aspire injects PORT for HTTP endpoint configuration

  • GET / - API information
  • GET /health - Health check
  • GET /items - List all items
  • GET /items/{id} - Get item by ID
  • POST /items - Create new item
  • PUT /items/{id} - Update item
  • DELETE /items/{id} - Delete item

This sample keeps the API intentionally small for demo purposes:

  • It does not implement authentication or authorization.
  • Data is stored only in memory and is lost when the process restarts.
  • The request body, item name, and in-memory item count limits are illustrative safeguards, not production capacity planning.
  • External HTTP endpoints are enabled to make the demo easy to run and inspect.
  • Production services should add real authentication, authorization, rate limiting, persistent storage, and monitoring appropriate for their threat model.

Related references: