Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/public/images/tutorial-scalar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
124 changes: 89 additions & 35 deletions docs/src/content/docs/getting-started/quick-start.mdx
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
---
title: "Quick Start"
description: "Set up AxisEndpoints in your ASP.NET Core project and create your first endpoint."
description: "Create a minimal AxisEndpoints project from scratch and verify it with Scalar."
---

import { Steps } from '@astrojs/starlight/components';

<Steps>
1. **Create a project**
1. **Create a new project**

```sh
dotnet new webapi -n MyApi
cd MyApi
dotnet new webapi -n AxisEndpoints.Tutorial
cd AxisEndpoints.Tutorial
```

2. **Install AxisEndpoints**
2. **Install the packages**

```sh
dotnet add package AxisEndpoints
dotnet add package Scalar.AspNetCore
```

3. **Set up Program.cs**
`AxisEndpoints` provides endpoint discovery and mapping. `Scalar.AspNetCore` gives you a browser-based API reference so you can verify the endpoint immediately.

Update `Program.cs` as shown below. `AddAxisEndpoints()` scans the entry assembly and automatically registers every class that implements the `IEndpoint` interface in the DI container. `MapAxisEndpoints()` maps the registered endpoints to the Minimal API pipeline.
3. **Replace `Program.cs`**

Filter classes that implement `IEndpointFilter` are also registered automatically through assembly scanning.
Use the same minimal setup as [`tests/AxisEndpoints.Tutorial/Program.cs`](https://github.com/sheepla/AxisEndpoints/blob/master/tests/AxisEndpoints.Tutorial/Program.cs):

`AddAxisEndpoints()` scans the entry assembly and registers endpoint classes in DI. `MapAxisEndpoints()` then maps those endpoints into the Minimal API pipeline.

```csharp
using AxisEndpoints.Extensions;
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -37,63 +41,113 @@ import { Steps } from '@astrojs/starlight/components';

app.MapOpenApi();
app.MapAxisEndpoints();
app.MapScalarApiReference();

app.Run();
```

4. **Create your first endpoint**
4. **Add your first endpoint**

Create `Features/Hello/HelloEndpoint.cs` and paste in the tutorial endpoint below.

Create a new class `CreateUserEndpoint` that implements `IEndpoint<CreateUserRequest, Response<CreateUserResponse>>` at `CreateUserEndpoint.cs`. This endpoint will handle POST requests to create a new user.
```text
AxisEndpoints.Tutorial/
|- Features/
| \- Hello/
| \- HelloEndpoint.cs
\- Program.cs
```

```csharp
public class CreateUserRequest
using AxisEndpoints;
using System.Net;

namespace AxisEndpoints.Tutorial.Features.Hello;

public record HelloRequest
{
public required string Name { get; init; }
public required string Email { get; init; }
public required string Name { get; set; } = string.Empty;
}

public class CreateUserResponse
public record HelloResponse
{
public required int Id { get; init; }
public required string Message { get; set; } = string.Empty;
}

public class CreateUserEndpoint : IEndpoint<CreateUserRequest, Response<CreateUserResponse>>
public class HelloEndpoint(ILogger<HelloEndpoint> logger) : IEndpoint<HelloRequest, IResult>
{
private readonly IUserRepository _repository;

public CreateUserEndpoint(IUserRepository repository) => _repository = repository;

public void Configure(IEndpointConfiguration config)
{
config.Post("/users")
.Tags("Users")
.Summary("Create a new user");
config
.Get("/hello")
.ProducesSuccess<HelloResponse>()
.ProducesError(HttpStatusCode.BadRequest)
.Summary("Hello")
.Description("This endpoint takes a name as input and returns a greeting message.");
}

public async Task<Response<CreateUserResponse>> HandleAsync(
CreateUserRequest request,
public Task<IResult> HandleAsync(
HelloRequest request,
CancellationToken cancel)
{
var id = await _repository.CreateAsync(request.Name, request.Email, cancel);

return new Response<CreateUserResponse>
if (string.IsNullOrWhiteSpace(request.Name))
{
StatusCode = HttpStatusCode.Created,
Headers = [("Location", $"/users/{id}")],
Body = new CreateUserResponse { Id = id },
};
logger.LogWarning("Rejected request to /hello because the name was missing.");
return Task.FromResult(Results.Problem(
title: "Name is required",
detail: "Provide a non-empty name query parameter.",
statusCode: StatusCodes.Status400BadRequest
));
}

logger.LogInformation("Received request to /hello with name: {Name}", request.Name);

return Task.FromResult(
Results.Json(new HelloResponse
{
Message = $"Hello, {request.Name}!"
})
);
}
}
```

5. **Run and verify**
Because this is a `GET` endpoint, `HelloRequest.Name` is bound from the query string. A request to `/hello?name=Alice` will populate `request.Name` with `Alice`.

5. **Run the app**

```sh
dotnet run
```

Send a POST request to `http://localhost:5000/users` to verify that the endpoint works.
6. **Verify the endpoint**

Open the Scalar API reference at `http://localhost:{port}/scalar` and try `GET /hello` with a `name` query parameter.

You can also call the endpoint directly:

```sh
curl "http://localhost:{port}/hello?name=Alice"
```

The response should look like this:

```json
{
"message": "Hello, Alice!"
}
```

</Steps>

For more details on defining endpoints, see the [Defining Endpoints](/guides/defining-endpoints/) guide.
## What You Should See

The tutorial project included in this repository uses the same setup and exposes the Scalar UI after startup.

<img
src="/images/tutorial-scalar.png"
alt="Scalar API reference showing the tutorial hello endpoint"
style={{ borderRadius: '0.75rem', border: '1px solid var(--sl-color-hairline-light)', width: '100%' }}
/>

For more details on endpoint structure and request binding, see [Defining Endpoints](/guides/defining-endpoints/) and [Request Binding](/guides/request-binding/).
76 changes: 46 additions & 30 deletions docs/src/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,50 @@ hero:
variant: minimal
---

import { Card, CardGrid } from '@astrojs/starlight/components';
import { Card, CardGrid } from "@astrojs/starlight/components";

## About

**AxisEndpoints** is a DSL for implementing the Request-Endpoint-Response (REPR) pattern in ASP.NET Core. It consolidates each API endpoint into a self-contained class with a clear, explicit programming interface.

```csharp
public class CreateUserEndpoint : IEndpoint<CreateUserRequest, Response<CreateUserResponse>>
using AxisEndpoints;

namespace AxisEndpoints.Tutorial.Features.Hello;

public record HelloRequest
{
private readonly IUserRepository _repository;
public required string Name { get; set; } = string.Empty;
}

public CreateUserEndpoint(IUserRepository repository) => _repository = repository;
public record HelloResponse
{
public required string Message { get; set; } = string.Empty;
}

public class HelloEndpoint(ILogger<HelloEndpoint> logger)
: IEndpoint<HelloRequest, Response<HelloResponse>>
{
public void Configure(IEndpointConfiguration config)
{
config.Post("/users")
.Tags("Users")
.Summary("Create a new user");
config
.Get("/hello")
.Summary("Hello")
.Description("This endpoint takes a name as input and returns a greeting message.");
}

public async Task<Response<CreateUserResponse>> HandleAsync(
CreateUserRequest request,
public Task<Response<HelloResponse>> HandleAsync(
HelloRequest request,
CancellationToken cancel)
{
var id = await _repository.CreateAsync(request.Name, request.Email, cancel);

return new Response<CreateUserResponse>
{
StatusCode = HttpStatusCode.Created,
Headers = [("Location", $"/users/{id}")],
Body = new CreateUserResponse { Id = id },
};
logger.LogInformation("Received request to /hello with name: {Name}", request.Name);

return Task.FromResult(
new Response<HelloResponse>
{
Body = new HelloResponse { Message = $"Hello, {request.Name}!" },
}
);
}
}
```
Expand All @@ -65,7 +77,7 @@ ASP.NET Core offers three approaches to building Web APIs. Each involves differe
| | Minimal API | Controller | REPR Pattern (AxisEndpoints) |
| ------------------- | --------------------------------------------- | ------------------------------------------- | ---------------------------------------------- |
| **Structure** | Functions registered inline | Methods grouped in a class | One class per endpoint |
| **Scalability** | ⚠ Can become hard to manage as endpoints grow | ⚠ Controllers can grow bloated over time | ✅ Each endpoint stays self-contained |
| **Scalability** | ⚠ Can become hard to manage as endpoints grow | ⚠ Controllers can grow bloated over time | ✅ Each endpoint stays self-contained |
| **Coupling** | Low — but no enforced structure | Medium — CRUD operations share a controller | Low — slices are independent by design |
| **Learning curve** | Low | Medium (MVC conventions) | Medium (built on Minimal API) |
| **Best suited for** | Small services, prototypes | CRUD-heavy APIs familiar to MVC developers | Feature-rich APIs, Vertical Slice Architecture |
Expand All @@ -82,16 +94,20 @@ To implement the REPR pattern in ASP.NET Core, you can either write a thin wrapp
## Next steps

<CardGrid>
<Card title="Installation" icon="setting">
Get AxisEndpoints installed in your project. See the [Installation guide](/getting-started/installation/).
</Card>
<Card title="Guides" icon="open-book">
Learn how to define endpoints, bind requests, handle responses, and more. See the [Guides](/guides/defining-endpoints/).
</Card>
<Card title="CSV Extension" icon="document">
Add typed CSV import and export to your endpoints with the optional CsvHelper extension. See the [CSV Helper extension](/extensions/csv-helper/).
</Card>
<Card title="FAQ" icon="comment">
Find answers to common questions in the [FAQ](/faq/).
</Card>
<Card title="Installation" icon="setting">
Get AxisEndpoints installed in your project. See the [Installation
guide](/getting-started/installation/).
</Card>
<Card title="Guides" icon="open-book">
Learn how to define endpoints, bind requests, handle responses, and more.
See the [Guides](/guides/defining-endpoints/).
</Card>
<Card title="CSV Extension" icon="document">
Add typed CSV import and export to your endpoints with the optional
CsvHelper extension. See the [CSV Helper
extension](/extensions/csv-helper/).
</Card>
<Card title="FAQ" icon="comment">
Find answers to common questions in the [FAQ](/faq/).
</Card>
</CardGrid>
2 changes: 1 addition & 1 deletion tests/AxisEndpoints.Example/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
// OpenAPI document available at /scalar/v1
// OpenAPI document available at /scalar
app.MapScalarApiReference();
}

Expand Down
Loading
Loading