Skip to content

Commit c80a699

Browse files
committed
Add README with badges and docs
1 parent b8cdd24 commit c80a699

1 file changed

Lines changed: 152 additions & 1 deletion

File tree

README.md

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,152 @@
1-
# Endpointer
1+
# Endpointer
2+
3+
[![Build](https://github.com/stephanprobst/Endpointer/actions/workflows/build.yml/badge.svg)](https://github.com/stephanprobst/Endpointer/actions/workflows/build.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![netstandard2.0](https://img.shields.io/badge/netstandard-2.0-blue)](https://docs.microsoft.com/en-us/dotnet/standard/net-standard)
6+
[![Roslyn](https://img.shields.io/badge/Roslyn-Source%20Generator-blueviolet)](https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/)
7+
8+
A **C# source generator** for ASP.NET Core Minimal APIs implementing the **REPR (Request-Endpoint-Response) pattern**.
9+
10+
Endpointer is a thin layer above ASP.NET Core - not a framework. It generates the boilerplate at compile time with no reflection, while you keep full control over your endpoints.
11+
12+
## Features
13+
14+
- **Zero runtime overhead** - All code is generated at compile time
15+
- **REPR pattern** - Clean separation with Request, Endpoint, and Response in one file
16+
- **Automatic DI registration** - Primary constructor parameters are auto-registered
17+
- **Automatic route mapping** - All endpoints discovered and mapped via source generation
18+
- **Native ASP.NET Core** - Uses `TypedResults`, `IEndpointRouteBuilder`, and standard middleware
19+
- **Incremental generator** - Fast builds with Roslyn's latest `IIncrementalGenerator` API
20+
- **No reflection** - Everything resolved at compile time
21+
22+
## Quick Start
23+
24+
### 1. Install the package
25+
26+
```bash
27+
dotnet add package Endpointer
28+
```
29+
30+
### 2. Create an endpoint
31+
32+
```csharp
33+
using Microsoft.AspNetCore.Http.HttpResults;
34+
35+
public class GetTimeEndpoint(TimeProvider timeProvider)
36+
{
37+
public record GetTimeResponse(DateTimeOffset CurrentTime);
38+
39+
public class Endpoint : IEndpoint
40+
{
41+
public void MapEndpoint(IEndpointRouteBuilder endpoints)
42+
{
43+
endpoints.MapGet("/time", (GetTimeEndpoint ep) => ep.Handle());
44+
}
45+
}
46+
47+
public Ok<GetTimeResponse> Handle()
48+
{
49+
return TypedResults.Ok(new GetTimeResponse(timeProvider.GetUtcNow()));
50+
}
51+
}
52+
```
53+
54+
### 3. Register in Program.cs
55+
56+
```csharp
57+
var builder = WebApplication.CreateBuilder(args);
58+
59+
builder.Services.AddEndpointer(); // Generated - registers all endpoint classes
60+
61+
var app = builder.Build();
62+
63+
app.MapEndpointer(); // Generated - maps all endpoints
64+
65+
await app.RunAsync();
66+
```
67+
68+
That's it! The source generator discovers all `IEndpoint` implementations and generates the registration code.
69+
70+
## How It Works
71+
72+
Endpointer uses Roslyn's incremental source generator to:
73+
74+
1. **Discover endpoints** - Finds all nested classes implementing `IEndpoint`
75+
2. **Extract metadata** - Captures the outer class name and its primary constructor parameters
76+
3. **Generate registration** - Creates extension methods for DI and route mapping
77+
78+
### Generated Code
79+
80+
The generator produces two files:
81+
82+
**IEndpoint.g.cs** - The marker interface:
83+
```csharp
84+
public interface IEndpoint
85+
{
86+
void MapEndpoint(IEndpointRouteBuilder endpoints);
87+
}
88+
```
89+
90+
**EndpointerRegistration.g.cs** - Extension methods:
91+
```csharp
92+
public static class EndpointerExtensions
93+
{
94+
public static IServiceCollection AddEndpointer(this IServiceCollection services)
95+
{
96+
services.AddScoped<GetTimeEndpoint>();
97+
services.AddScoped<GetUserEndpoint>();
98+
services.AddScoped<CreateUserEndpoint>();
99+
// ... all discovered endpoints
100+
return services;
101+
}
102+
103+
public static IEndpointRouteBuilder MapEndpointer(this IEndpointRouteBuilder endpoints)
104+
{
105+
new GetTimeEndpoint.Endpoint().MapEndpoint(endpoints);
106+
new GetUserEndpoint.Endpoint().MapEndpoint(endpoints);
107+
new CreateUserEndpoint.Endpoint().MapEndpoint(endpoints);
108+
// ... all discovered endpoints
109+
return endpoints;
110+
}
111+
}
112+
```
113+
114+
## The REPR Pattern
115+
116+
REPR (Request-Endpoint-Response) organizes API code by feature rather than by layer:
117+
118+
```
119+
Endpoints/
120+
├── Users/
121+
│ ├── CreateUserEndpoint.cs # POST /users
122+
│ ├── GetUserEndpoint.cs # GET /users/{id}
123+
│ ├── UpdateUserEndpoint.cs # PUT /users/{id}
124+
│ └── DeleteUserEndpoint.cs # DELETE /users/{id}
125+
└── Health/
126+
└── HealthEndpoint.cs # GET /health
127+
```
128+
129+
Each file contains:
130+
- **Request** - Input DTOs (records)
131+
- **Endpoint** - Route mapping (nested `IEndpoint` class)
132+
- **Response** - Output DTOs (records)
133+
- **Handler** - Business logic (methods on outer class)
134+
135+
## Requirements
136+
137+
- **.NET 10.0** or later (for the application)
138+
- The generator itself targets **netstandard2.0** for broad compatibility
139+
140+
## Building
141+
142+
```bash
143+
# Build
144+
dotnet build src/Endpointer.slnx
145+
146+
# Test
147+
dotnet test --solution src/Endpointer.slnx
148+
```
149+
150+
## License
151+
152+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)