mukut1994 / MK94.CodeGenerator

MIT License
0 stars 0 forks source link

Ability to generate thin wrapper controllers #47

Open mithileshz opened 5 months ago

mithileshz commented 5 months ago

If we have a service that should be exposed as-is on the controller layer, we can implement a generator that creates a thin controller class where all it does is call the service implementation.

Given the following service implementation in the generator classes

[ImplementedByCore]
[File("Service")]
[ControllerWrapper] <-- THIS IS NEW
public interface IPizzaService
{
    Task<Guid> Create(Pizza pizza);
}

will generate

public class PizzaController(IPizzaService pizzaService)
{
    public async Task<Guid> Create(Pizza pizza)
    {
        return await pizzaService.Create(pizza);
    }
}

Questions:

mukut1994 commented 5 months ago

This would become a lot more useful if it ran based on the existing ControllerModule.

so the existing module would generate the partial stubs like so

[ImplementedByCore]
[File("Service")]
[ControllerWrapper] <-- This should be allowed on interface/method
public interface IPizzaService
{
    Task<Guid> Create(Pizza pizza);
}

// Created by `ServiceWrapperModule`
public partial class PizzaController(IPizzaService pizzaService)
{
    public partial async Task<Guid> Create(Pizza pizza)
    {
        return await pizzaService.Create(pizza);
    }
}

// Created by `ControllerModule`
// This fills in the ASP.NET attributes for us
[Route("api/[controller]/[method]"]
public partial class PizzaController(IPizzaService pizzaService)
{
    // technically speaking, the `ServiceWrapperModule` could just create the body here instead of defining yet another partial class
    public partial Task<Guid> Create([FromBody] Pizza pizza);
}

so if in the future we want to add another method to the defintion, we can pick only some methods like so

[ImplementedByCore]
[File("Service")]
public interface IPizzaService
{
    // No longer on the interface; we just want this method to be auto implemented
    [ControllerWrapper]
    Task<Guid> Create(Pizza pizza);

    // This method has to be implemented by tthe dev
    Task<Guid> Read(Pizza pizza);
}

// Created by `ServiceWrapperModule`; no Read method because the attribute is only on the class itself
public partial class PizzaController(IPizzaService pizzaService)
{
    public partial async Task<Guid> Create(Pizza pizza)
    {
        return await pizzaService.Create(pizza);
    }
}

// Created by `ControllerModule`
// This fills in the ASP.NET attributes for us
[Route("api/[controller]/[method]"]
public partial class PizzaController(IPizzaService pizzaService)
{
    // Auto implemented above 
    public partial Task<Guid> Create([FromBody] Pizza pizza);
    // Needs a person to fill in the body
    public partial Task<Guid> Read([FromBody] Pizza pizza);

}
mithileshz commented 5 months ago

I was thinking in the following scenario -

// Created by `ControllerModule`
// This fills in the ASP.NET attributes for us
[Route("api/[controller]/[method]"]
public partial class PizzaController(IPizzaService pizzaService)
{
    // technically speaking, the `ServiceWrapperModule` could just create the body here instead of defining yet another partial class
    public partial Task<Guid> Create([FromBody] Pizza pizza);
}

The body of the controller would be implemented by default which calls the service directly. So we don't need to have an implementation of the controller and it's done by the code generator. Not sure if it should be an option that is configurable?

// Created by `ControllerModule`
// This fills in the ASP.NET attributes for us
[Route("api/[controller]/[method]"]
public partial class PizzaController(IPizzaService pizzaService)
{
    [HttpPost] public Task<Guid> Create([FromBody] Pizza pizza) => pizzaService.Create(pizza);
}