Skip to content

Generates Controllers, DTOs and MediatR Requests from a given OpenAPI Spec file to support API First development.

License

Notifications You must be signed in to change notification settings

alexcampana/ApiFirstMediatR

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ApiFirstMediatR

CI NuGet

Generates Controllers, DTOs and MediatR Requests from a given OpenAPI Spec file to support API First development. Business logic implementation is handled by MediatR handlers that implement the generated MediatR Requests.

Code is generated using a Roslyn based Source Generator. To find out more about Roslyn Source Generators go here: https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview

Currently supports ASP.NET Core 6.0 and 7.0 and OpenAPI Spec version 3 and 2 in both yaml and json formats.

Installation

dotnet add package ApiFirstMediatR.Generator

Register your OpenAPI spec file by adding the following to your .csproj:

    <ItemGroup>
        <!-- Registers the OpenAPI spec -->
        <AdditionalFiles Include="api_spec.json" />
    </ItemGroup>

Hello World Example

Hello World OpenAPI spec:

openapi: 3.0.1
info:
  title: HelloWorld API
  version: v1
paths:
  /api/HelloWorld:
    get:
      tags:
        - HelloWorld
      operationId: GetHelloWorld
      description: Gets a HelloWorld Message
      parameters: []
      responses:
        200:
          description: Hello world!
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HelloWorldDto'
components:
  schemas:
    HelloWorldDto:
      type: object
      properties:
        message:
          type: string
          nullable: true
security: []

The source generators will then generate the following based on he given OpenAPI spec file:

// <auto-generated/>
using System.Text.Json.Serialization;

namespace compilation.Dtos
{
    public class HelloWorldDto 
    {
        [JsonPropertyName("message")]
        public string? Message { get; set; }
    }
}
// <auto-generated/>
#nullable enable
using MediatR;
using compilation.Dtos;

namespace compilation.Requests
{
    /// <summary>
    /// Gets a HelloWorld Message
    /// </summary>
    /// <returns>Hello world!</returns>
    public sealed class GetHelloWorldQuery : IRequest<HelloWorldDto>
    {
        public GetHelloWorldQuery()
        {
        }
    }
}
// <auto-generated/>
#nullable enable
using MediatR;
using Microsoft.AspNetCore.Mvc;
using compilation.Dtos;
using compilation.Requests;

namespace compilation.Controllers
{
    public sealed class ApiController : Controller
    {
        private readonly IMediator _mediator;

        public ApiController(IMediator mediator)
        {
            _mediator = mediator;
        }
        
        /// <summary>
        /// Gets a HelloWorld Message
        /// </summary>
        /// <returns>Hello world!</returns>
        [HttpGet("/api/HelloWorld")]
        public async Task<ActionResult> GetHelloWorld(CancellationToken cancellationToken)
        {
            var request = new GetHelloWorldQuery();
            var response = await _mediator.Send(request, cancellationToken);
            return Ok(response);
        }
    }
}

To implement the Hello World endpoint create the following handler:

using HelloWorld.Dtos;
using HelloWorld.Requests;
using MediatR;

namespace HelloWorld.Handlers
{
    public sealed class GetHelloWorldQueryHandler : IRequestHandler<GetHelloWorldQuery, HelloWorldDto>
    {
        public Task<HelloWorldDto> Handle(GetHelloWorldQuery query, CancellationToken cancellationToken)
        {
            // Endpoint implementation goes here
        }
    }
}

Viewing the generated files

Visual Studio

In the solution explorer expand Project -> Dependencies -> Analyzers -> ApiFirstMediatR.Generator -> ApiFirstMediatR.Generator.ApiSourceGenerator.

Rider

In the explorer expand Project -> Dependencies -> .NET 6.0 -> Source Generators -> ApiFirstMediatR.Generator.ApiSourceGenerator

VSCode

Add the following to your .csproj

    <!-- Begin VSCode Compatibility -->
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
    <ItemGroup>
        <Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
    </ItemGroup>

    <Target Name="CleanSourceGeneratedFiles" BeforeTargets="BeforeRebuild" DependsOnTargets="$(BeforeBuildDependsOn)">
        <RemoveDir Directories="$(CompilerGeneratedFilesOutputPath)" />
    </Target>
    <!-- End VSCode Compatibility -->

This will force the generators to output the generated files to the Generated directory, but notify the compiler to ignore the generated files and continue to use the normal Roslyn Source Generator compile process. Adding the Generated directory to your .gitignore is recommended.

Configuration

MSBuild Options

Available MSBuild properties:

Property Default Available Options Description
ApiFirstMediatR_SerializationLibrary System.Text.Json System.Text.Json, Newtonsoft.Json Serialization Library that the generated code should use.
ApiFirstMediatR_RequestBodyName Body string The name that's used for request bodies in mediatr requests.

To set an MSBuild option you need to add the property and value to your csproj file.

Example:

    <PropertyGroup>
        <ApiFirstMediatR_SerializationLibrary>Newtonsoft.Json</ApiFirstMediatR_SerializationLibrary>
    </PropertyGroup>

About

Generates Controllers, DTOs and MediatR Requests from a given OpenAPI Spec file to support API First development.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published