diff --git a/src/frontend/src/components/SimpleAppHostCode.astro b/src/frontend/src/components/SimpleAppHostCode.astro index 0f39739d..d49abc52 100644 --- a/src/frontend/src/components/SimpleAppHostCode.astro +++ b/src/frontend/src/components/SimpleAppHostCode.astro @@ -4,15 +4,17 @@ import type { MarkerDefinition } from '@astrojs/starlight/expressive-code'; export type MarkerValueType = MarkerDefinition | MarkerDefinition[] | undefined; export type CollapseValueType = string | string[] | undefined; +export type LangType = 'csharp' | 'python' | 'nodejs' | 'go' | 'java'; interface CodeProps { + lang?: LangType; mark?: MarkerValueType; collapse?: CollapseValueType; } -const { mark, collapse } = Astro.props as CodeProps; +const { lang = 'csharp', mark, collapse } = Astro.props as CodeProps; -const cs = ` +const csharp = ` var builder = DistributedApplication.CreateBuilder(args); // Add database resource @@ -32,12 +34,110 @@ builder.AddViteApp("frontend", "../frontend") builder.Build().Run(); `; + +const python = ` +var builder = DistributedApplication.CreateBuilder(args); + +// Add database resource +var postgres = builder.AddPostgres("db") + .AddDatabase("appdata") + .WithDataVolume(); + +// Add API service and reference the database +var api = builder.AddUvicornApp("api", "../api", "main:app") + .WithUv() + .WithReference(postgres) + .WaitFor(postgres); + +// Add frontend service and reference the API +builder.AddViteApp("frontend", "../frontend") + .WithHttpEndpoint(env: "PORT") + .WithReference(api); + +builder.Build().Run(); +`; + +const javascript = ` +var builder = DistributedApplication.CreateBuilder(args); + +// Add database resource +var postgres = builder.AddPostgres("db") + .AddDatabase("appdata") + .WithDataVolume(); + +// Add API service and reference the database +var api = builder.AddNodeApp("api", "../api", "server.js") + .WithNpm() + .WithReference(postgres) + .WaitFor(postgres); + +// Add frontend service and reference the API +builder.AddViteApp("frontend", "../frontend") + .WithHttpEndpoint(env: "PORT") + .WithReference(api); + +builder.Build().Run(); +`; + +const golang = ` +var builder = DistributedApplication.CreateBuilder(args); + +// Add database resource +var postgres = builder.AddPostgres("db") + .AddDatabase("appdata") + .WithDataVolume(); + +// Add API service and reference the database +var api = builder.AddGolangApp("api", "../api") + .WithHttpEndpoint(env: "PORT") + .WithReference(postgres) + .WaitFor(postgres); + +// Add frontend service and reference the API +builder.AddViteApp("frontend", "../frontend") + .WithHttpEndpoint(env: "PORT") + .WithReference(api); + +builder.Build().Run(); +`; + +const java = ` +var builder = DistributedApplication.CreateBuilder(args); + +// Add database resource +var postgres = builder.AddPostgres("db") + .AddDatabase("appdata") + .WithDataVolume(); + +// Add API service and reference the database +var api = builder.AddSpringApp("api", "../api", "otel.jar") + .WithHttpEndpoint(port: 8080) + .WithReference(postgres) + .WaitFor(postgres); + +// Add frontend service and reference the API +builder.AddViteApp("frontend", "../frontend") + .WithHttpEndpoint(env: "PORT") + .WithReference(api); + +builder.Build().Run(); +`; + +const codeMap: Record = { + csharp, + python, + nodejs: javascript, + go: golang, + java, +}; + +const code = codeMap[lang]; --- + ## Defining your architecture Consider a simple three-tier architecture where the front end talks to an API, and the API talks to a database: + + ```mermaid architecture-beta @@ -25,9 +41,141 @@ architecture-beta frontend:R --> L:api ``` +This architecture demonstrates a **.NET API** connecting to a **PostgreSQL database**, with a **React front end** consuming the API. The .NET API uses ASP.NET Core and connects to PostgreSQL using Entity Framework or a connection string. The React front end is built with Vite and communicates with the API over HTTP. + +To build this architecture step-by-step, see the [Build your first app](/get-started/first-app/?lang=csharp) quickstart. + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[PostgreSQL] + service api(logos:python)[API service] + service frontend(logos:react)[React front end] + + api:R --> L:db + frontend:R --> L:api +``` + +This architecture demonstrates a **Python API** (using FastAPI/Uvicorn) connecting to a **PostgreSQL database**, with a **React front end** consuming the API. The Python API uses frameworks like FastAPI or Flask and connects to PostgreSQL using libraries like psycopg2 or SQLAlchemy. The React front end is built with Vite and communicates with the API over HTTP. + +To build this architecture step-by-step, see the [Build your first app](/get-started/first-app/?lang=python) quickstart. + + + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[PostgreSQL] + service api(logos:nodejs-icon)[API service] + service frontend(logos:react)[React front end] + + api:R --> L:db + frontend:R --> L:api +``` + +This architecture demonstrates a **Node.js API** connecting to a **PostgreSQL database**, with a **React front end** consuming the API. The Node.js API uses frameworks like Express or Fastify and connects to PostgreSQL using libraries like pg or Prisma. The React front end is built with Vite and communicates with the API over HTTP. + + + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[PostgreSQL] + service api(logos:go)[API service] + service frontend(logos:react)[React front end] + + api:R --> L:db + frontend:R --> L:api +``` + +This architecture demonstrates a **Go API** connecting to a **PostgreSQL database**, with a **React front end** consuming the API. The Go API uses the standard library's `net/http` package or frameworks like Gin or Echo and connects to PostgreSQL using libraries like pgx or database/sql. The React front end is built with Vite and communicates with the API over HTTP. + + + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[PostgreSQL] + service api(logos:java)[API service] + service frontend(logos:react)[React front end] + + api:R --> L:db + frontend:R --> L:api +``` + +This architecture demonstrates a **Java API** (using Spring Boot) connecting to a **PostgreSQL database**, with a **React front end** consuming the API. The Java API uses Spring Boot with Spring Data JPA and connects to PostgreSQL using JDBC or Spring Data. The React front end is built with Vite and communicates with the API over HTTP. + + + + + You can represent that architecture in an AppHost like this: - + + + + + + + + + + + + + + + + +The AppHost models your distributed application declaratively. Each tab above shows the same three-tier architecture—**PostgreSQL database**, **API service**, and **React front end**—but with different API implementations. Switching tabs changes only the API resource type: + + + +Uses `AddProject()` to reference a .NET project. + + + + +Uses `AddUvicornApp()` with `WithUv()` for ASGI apps like FastAPI. + + + + +Uses `AddNodeApp()` with `WithNpm()` for Node.js applications. + + + + +Uses `AddGolangApp()` for Go applications. + + + + +Uses `AddSpringApp()` for Spring Boot applications. + + + +In all cases, the PostgreSQL database and React front end remain identical. Aspire's `WithReference()` method establishes dependencies between resources, and `WaitFor()` ensures services start in the correct order. Aspire presents the same, consistent model regardless of the language or framework used: services, resources, and the connections between them. @@ -35,7 +183,21 @@ Aspire presents the same, consistent model regardless of the language or framewo Below we highlight the key parts of a typical AppHost to explain what each step does. - + + + + + + + + + + + + + + + In the non-collapsed lines you: @@ -53,7 +215,21 @@ The AppHost is the blueprint for your distributed application—Aspire manages t With the builder ready, define resources and services. The snippet below shows how to add a PostgreSQL server and a database: - + + + + + + + + + + + + + + + How this works: @@ -70,14 +246,64 @@ How this works: Next, register the API service and wire it to the PostgreSQL resource: - + + + + + + + + + + + + + + + What this does: + + - `AddProject("api")` registers the API project as a service named `api`. - `WithReference(postgres)` injects connection details (host, port, credentials, connection string) into the API configuration. - `WaitFor(postgres)` delays the API startup until PostgreSQL is healthy, avoiding brittle startup timing issues. + + + +- `AddUvicornApp("api", "../api", "main:app")` registers a Uvicorn-based Python app as a service named `api`, pointing to the `main:app` entry point. +- `WithUv()` configures the app to use the [uv](https://docs.astral.sh/uv/) package manager for dependency installation. +- `WithReference(postgres)` injects connection details into the API configuration. +- `WaitFor(postgres)` delays the API startup until PostgreSQL is healthy. + + + + +- `AddNodeApp("api", "../api", "server.js")` registers a Node.js app as a service named `api`, with `server.js` as the entry point. +- `WithNpm()` configures the app to use npm for dependency installation. +- `WithReference(postgres)` injects connection details into the API configuration. +- `WaitFor(postgres)` delays the API startup until PostgreSQL is healthy. + + + + +- `AddGolangApp("api", "../api")` registers a Go app as a service named `api`. +- `WithHttpEndpoint(env: "PORT")` configures the port and sets the PORT environment variable. +- `WithReference(postgres)` injects connection details into the API configuration. +- `WaitFor(postgres)` delays the API startup until PostgreSQL is healthy. + + + + +- `AddSpringApp("api", "../api", "../agents/opentelemetry-javaagent.jar")` registers a Spring Boot app as a service named `api`, specifying the OpenTelemetry agent path. +- `WithHttpEndpoint(port: 8080)` exposes the Spring Boot app on port 8080. +- `WithReference(postgres)` injects connection details into the API configuration. +- `WaitFor(postgres)` delays the API startup until PostgreSQL is healthy. + + + Now that the `api` service is defined, you can attach the front end. #### Adding a front end resource @@ -88,7 +314,21 @@ Register the front end project, declare its dependency on the API, and let the A This example uses a Node.js (React) front end, but Aspire treats front ends as executable services—any language or framework works. - + + + + + + + + + + + + + + + Key points: @@ -102,6 +342,8 @@ In short: define the backend first (DB → API), then point the UI at the API. T These dependencies and connections are automatically managed by Aspire. The AppHost generates configuration values like connection strings and endpoints, injecting them into services as needed. in the AppHost when you add resources, you name them (e.g., `db`, `api`, `front end`); Aspire uses these names for DNS resolution, so services can communicate using predictable addresses. Consuming services also rely on these names for configuration injection. + + ```mermaid architecture-beta @@ -117,6 +359,90 @@ architecture-beta epr:L <-- R:frontend ``` +The .NET API receives a **ConnectionStringReference** from PostgreSQL and publishes an **EndpointReference** that the React front end consumes. This creates a clear dependency chain: `PostgreSQL → .NET API → React front end`. + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[pg] + service epr(iconoir:server-connection)[Endpoint Reference] + service api(logos:python)[api] + service ctr(iconoir:server-connection)[Connection String Reference] + service frontend(logos:react)[front end] + + db:L <-- R:ctr + ctr:L <-- R:api + api:L <-- R:epr + epr:L <-- R:frontend +``` + +The Python API receives a **ConnectionStringReference** from PostgreSQL and publishes an **EndpointReference** that the React front end consumes. This creates a clear dependency chain: `PostgreSQL → Python API → React front end`. + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[pg] + service epr(iconoir:server-connection)[Endpoint Reference] + service api(logos:nodejs-icon)[api] + service ctr(iconoir:server-connection)[Connection String Reference] + service frontend(logos:react)[front end] + + db:L <-- R:ctr + ctr:L <-- R:api + api:L <-- R:epr + epr:L <-- R:frontend +``` + +The Node.js API receives a **ConnectionStringReference** from PostgreSQL and publishes an **EndpointReference** that the React front end consumes. This creates a clear dependency chain: `PostgreSQL → Node.js API → React front end`. + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[pg] + service epr(iconoir:server-connection)[Endpoint Reference] + service api(logos:go)[api] + service ctr(iconoir:server-connection)[Connection String Reference] + service frontend(logos:react)[front end] + + db:L <-- R:ctr + ctr:L <-- R:api + api:L <-- R:epr + epr:L <-- R:frontend +``` + +The Go API receives a **ConnectionStringReference** from PostgreSQL and publishes an **EndpointReference** that the React front end consumes. This creates a clear dependency chain: `PostgreSQL → Go API → React front end`. + + + + +```mermaid +architecture-beta + + service db(logos:postgresql)[pg] + service epr(iconoir:server-connection)[Endpoint Reference] + service api(logos:java)[api] + service ctr(iconoir:server-connection)[Connection String Reference] + service frontend(logos:react)[front end] + + db:L <-- R:ctr + ctr:L <-- R:api + api:L <-- R:epr + epr:L <-- R:frontend +``` + +The Java API receives a **ConnectionStringReference** from PostgreSQL and publishes an **EndpointReference** that the React front end consumes. This creates a clear dependency chain: `PostgreSQL → Java API → React front end`. + + + **How these resources communicate**