{"id":13629267,"url":"https://github.com/JensDll/MinimalApiBuilder","last_synced_at":"2025-04-17T08:34:37.802Z","repository":{"id":103902312,"uuid":"579818313","full_name":"JensDll/MinimalApiBuilder","owner":"JensDll","description":"Reflectionless, source-generated, thin abstraction layer over the ASP.NET Core Minimal APIs interface","archived":false,"fork":false,"pushed_at":"2025-03-17T13:01:22.000Z","size":661,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-14T00:48:30.686Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JensDll.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-12-19T02:07:20.000Z","updated_at":"2025-02-03T13:25:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"6ce4cd5e-1b4a-4897-95bb-b0a72d0e8364","html_url":"https://github.com/JensDll/MinimalApiBuilder","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JensDll%2FMinimalApiBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JensDll%2FMinimalApiBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JensDll%2FMinimalApiBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JensDll%2FMinimalApiBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JensDll","download_url":"https://codeload.github.com/JensDll/MinimalApiBuilder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249326186,"owners_count":21251735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T22:01:06.116Z","updated_at":"2025-04-17T08:34:37.778Z","avatar_url":"https://github.com/JensDll.png","language":"C#","funding_links":[],"categories":["Content"],"sub_categories":["78. [MinimalApiBuilder](https://ignatandrei.github.io/RSCG_Examples/v2/docs/MinimalApiBuilder) , in the [API](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) category"],"readme":"# MinimalApiBuilder\n\n[![nuget](https://badgen.net/nuget/v/MinimalApiBuilder)](https://www.nuget.org/packages/MinimalApiBuilder)\n\nReflectionless, source-generated, thin abstraction layer over the\n[ASP.NET Core Minimal APIs](https://learn.microsoft.com/en-gb/aspnet/core/fundamentals/minimal-apis/overview)\ninterface.\n\n## How to Use\n\nBased on the Vertical Slice Architecture with `Feature` folder.\nThere is one class for every API endpoint. A basic example looks like the following:\n\n```csharp\nusing MinimalApiBuilder.Generator;\n\npublic partial class BasicEndpoint : MinimalApiBuilderEndpoint\n{\n    public static string Handle()\n    {\n        return \"Hello, World!\";\n    }\n}\n```\n\nThe endpoint class must be `partial`, inherit from `MinimalApiBuilderEndpoint`,\nand have a `static` `Handle` or `HandleAsync` method. The endpoint is mapped\nthrough the typical `IEndpointRouteBuilder` `Map\u003cVerb\u003e` extension methods:\n\n```csharp\napp.MapGet(\"/hello\", BasicEndpoint.Handle);\n```\n\nThis library depends on [`FluentValidation \u003e= 11`](https://github.com/FluentValidation/FluentValidation).\nAn endpoint can have a validated request object:\n\n```csharp\npublic struct BasicRequest\n{\n    public required string Name { get; init; }\n}\n\npublic partial class BasicRequestEndpoint : MinimalApiBuilderEndpoint\n{\n    public static string Handle([AsParameters] BasicRequest request)\n    {\n        return $\"Hello, {request.Name}!\";\n    }\n}\n\npublic class BasicRequestValidator : AbstractValidator\u003cBasicRequest\u003e\n{\n    public BasicRequestValidator()\n    {\n        RuleFor(static request =\u003e request.Name).MinimumLength(2);\n    }\n}\n```\n\nThe incremental generator will generate code to validate the request object before\nthe handler is called and return\na [`ValidationProblem`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.results.validationproblem)\nvalidation error result if the validation fails. To wire up the validation filters\nand to support\nthe [Request Delegate Generator](https://learn.microsoft.com/en-gb/aspnet/core/fundamentals/aot/request-delegate-generator/rdg),\nthe `Map` methods need to be wrapped by the `ConfigureEndpoints.Configure` helper,\nwhich expects a comma-separated list\nof [`RouteHandlerBuilder`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.routehandlerbuilder):\n\n```csharp\nusing static MinimalApiBuilder.Generator.ConfigureEndpoints;\n\nConfigure(app.MapGet(\"/hello/{name}\", BasicRequestEndpoint.Handle));\n```\n\nValidation\nin [custom binding](https://learn.microsoft.com/en-gb/aspnet/core/fundamentals/minimal-apis/parameter-binding#custom-binding)\nscenarios is also supported. For example, adapting the Microsoft\n[`BindAsync` sample](https://learn.microsoft.com/en-gb/aspnet/core/fundamentals/minimal-apis/parameter-binding?view=aspnetcore-8.0#bindasync):\n\n\u003cdetails\u003e\n\u003csummary\u003eShow example\u003c/summary\u003e\n\n```csharp\npublic record PagingData(string? SortBy, SortDirection SortDirection, int CurrentPage)\n{\n    private const string SortByKey = \"sortby\";\n    private const string SortDirectionKey = \"sortdir\";\n    private const string PageKey = \"page\";\n\n    public static ValueTask\u003cPagingData?\u003e BindAsync(HttpContext httpContext)\n    {\n        ProductsEndpoint endpoint =\n            httpContext.RequestServices.GetRequiredService\u003cProductsEndpoint\u003e();\n\n        SortDirection sortDirection = default;\n        int page = default;\n\n        if (httpContext.Request.Query.TryGetValue(SortDirectionKey,\n            out StringValues sortDirectionValues))\n        {\n            if (!Enum.TryParse(sortDirectionValues, ignoreCase: true, out sortDirection))\n            {\n                endpoint.AddValidationError(SortDirectionKey,\n                    \"Invalid sort direction. Valid values are 'default', 'asc', or 'desc'.\");\n            }\n        }\n        else\n        {\n            endpoint.AddValidationError(SortDirectionKey, \"Missing sort direction.\");\n        }\n\n        if (httpContext.Request.Query.TryGetValue(PageKey, out StringValues pageValues))\n        {\n            if (!int.TryParse(pageValues, out page))\n            {\n                endpoint.AddValidationError(PageKey, \"Invalid page number.\");\n            }\n        }\n        else\n        {\n            endpoint.AddValidationError(PageKey, \"Missing page number.\");\n        }\n\n        if (endpoint.HasValidationError)\n        {\n            return ValueTask.FromResult\u003cPagingData?\u003e(null);\n        }\n\n        PagingData result = new(httpContext.Request.Query[SortByKey], sortDirection, page);\n\n        return ValueTask.FromResult\u003cPagingData?\u003e(result);\n    }\n}\n\npublic enum SortDirection\n{\n    Default,\n    Asc,\n    Desc\n}\n\npublic partial class ProductsEndpoint : MinimalApiBuilderEndpoint\n{\n    public static string Handle(PagingData pageData)\n    {\n        return pageData.ToString();\n    }\n}\n```\n\n```csharp\nConfigure(app.MapGet(\"/products\", ProductsEndpoint.Handle));\n```\n\n\u003c/details\u003e\n\nUnfortunately, [`TryParse`](https://learn.microsoft.com/en-gb/aspnet/core/fundamentals/minimal-apis/parameter-binding#tryparse)\ncannot be validated this way as there is no easy way to access the\n`IServiceProvider` right now. To not short-circuit execution by\nthrowing an exception when returning `null` from `BindAsync`,\n[`ThrowOnBadRequest`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.routing.routehandleroptions.throwonbadrequest)\nneeds to be disabled:\n\n```csharp\nbuilder.Services.Configure\u003cRouteHandlerOptions\u003e(static options =\u003e\n{\n    options.ThrowOnBadRequest = false;\n});\n```\n\nEndpoints and validators need to be registered\nwith dependency injection. The following method adds them:\n\n```csharp\nbuilder.Services.AddMinimalApiBuilderEndpoints();\n```\n\n## Configuration\n\nUsers can add configuration through entries in `.editorconfig` or with\n[MSBuild properties](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-properties).\nThe following options are available,\nwith configuration snippets showing the default values:\n\n### `minimalapibuilder_assign_name_to_endpoint` (`true` | `false`)\n\nIf `true`, the generator will add a unique `public const string Name` field to\nthe endpoint classes and call\nthe [`WithName`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.routingendpointconventionbuilderextensions.withname)\nextension method when mapping them.\n\n```.editorconfig\nminimalapibuilder_assign_name_to_endpoint = false\n```\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cminimalapibuilder_assign_name_to_endpoint\u003efalse\u003c/minimalapibuilder_assign_name_to_endpoint\u003e\n\u003c/PropertyGroup\u003e\n```\n\n### `minimalapibuilder_validation_problem_type` (`string`)\n\nThe [type](https://datatracker.ietf.org/doc/html/rfc7807#section-3.1) of the\n[`ValidationProblem`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.results.validationproblem)\nvalidation error result.\n\n```.editorconfig\nminimalapibuilder_validation_problem_type = https://tools.ietf.org/html/rfc9110#section-15.5.1\n```\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cminimalapibuilder_validation_problem_type\u003ehttps://tools.ietf.org/html/rfc9110#section-15.5.1\u003c/minimalapibuilder_validation_problem_type\u003e\n\u003c/PropertyGroup\u003e\n```\n\n### `minimalapibuilder_validation_problem_title` (`string`)\n\nThe [title](https://datatracker.ietf.org/doc/html/rfc7807#section-3.1)\nof\nthe [`ValidationProblem`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.results.validationproblem)\nvalidation error result.\n\n```.editorconfig\nminimalapibuilder_validation_problem_title = One or more validation errors occurred.\n```\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cminimalapibuilder_validation_problem_title\u003eOne or more validation errors occurred.\u003c/minimalapibuilder_validation_problem_title\u003e\n\u003c/PropertyGroup\u003e\n```\n\n### `minimalapibuilder_model_binding_problem_type` (`string`)\n\nThe [type](https://datatracker.ietf.org/doc/html/rfc7807#section-3.1)\nof\nthe [`ValidationProblem`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.results.validationproblem)\nmodel binding error result.\n\n```.editorconfig\nminimalapibuilder_model_binding_problem_type = https://tools.ietf.org/html/rfc9110#section-15.5.1\n```\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cminimalapibuilder_model_binding_problem_type\u003ehttps://tools.ietf.org/html/rfc9110#section-15.5.1\u003c/minimalapibuilder_model_binding_problem_type\u003e\n\u003c/PropertyGroup\u003e\n```\n\n### `minimalapibuilder_model_binding_problem_title` (`string`)\n\nThe [title](https://datatracker.ietf.org/doc/html/rfc7807#section-3.1)\nof\nthe [`ValidationProblem`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.results.validationproblem)\nmodel binding error result.\n\n```.editorconfig\nminimalapibuilder_model_binding_problem_title = One or more model binding errors occurred.\n```\n\n```xml\n\u003cPropertyGroup\u003e\n  \u003cminimalapibuilder_model_binding_problem_title\u003eOne or more model binding errors occurred.\u003c/minimalapibuilder_model_binding_problem_title\u003e\n\u003c/PropertyGroup\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJensDll%2FMinimalApiBuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJensDll%2FMinimalApiBuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJensDll%2FMinimalApiBuilder/lists"}