Significance of Delegate Design Pattern in Swagger Generated Code?
Asked Answered
R

2

19

When i generate code for Spring from my swagger yaml , usually controller layer is generated using delegate pattern , such that for a single model three files are generated . For example , if i defined a model named Person in my swagger/open API yaml file , three files get generated as :

  1. PersonApi (interface that contains signatures of all person operations/methods)
  2. PersonApiDelegate ( interface that provides default implementation of all PersonApi methods . Meant to be overriden )
  3. PersonApiController (Which has a reference to PersonApiDelegate so that any implementation can override and provide custom implementation)

My question is for anyone who is familiar with building swagger/openapi generated code based apis that what is the significance of having such a pattern , instead of just exposing your service endpoints using a PersonController class , and not going through a PersonApi interface and then to a PersonApiDelegate and finally exposing the service through a PersonApiController ?

What is the valuable design extensibility we gain through this pattern ? I tried to find information from other resources on internet , but couldn't find a good answer in context of swagger first API development approach . Any insights on this will be really helpful .

Raman answered 20/2, 2021 at 17:41 Comment(2)
I am pretty sure you can generate your server without Delegate.. At work we only generate the API interface, which is then overridden by the controllerDivulge
Yes , we can by putting useLombok=false in open-api generator plugin . But i want to understand for which use-case we use this pattern ?Raman
A
23

First of all a clarification: as already mentioned in a comment, you are not forced to use the delegation. On the contrary, the default behavior of the Spring generator is to not use the delegation pattern, as you can easily check in the docs. In this case it will generate only the PersonApi interface and PersonApiController.

Coming to your question, why using delegation?

This allows you to write a class that implements PersonApiDelegate, that can be easily injected in the generated code, without any need to manually touch generated sources, and keeping the implementation safe from possible future changes in the code generation.

Let's think what could happen without delegation.

A naive approach would be to generate the sources and then write directly the implementation inside the generated PersonController. Of course the next time there is a need to run the generator, it would be a big mess. All the implementation would be lost...

A slightly better scenario, but not perfect, would be to write a class that extends PersonController. That would keep the implementation safe from being overwritten during generation, but would not protect it from future changes of the generation engine: as a bare minimum the implementation class would need to implement the PersonController constructor. Right now the constructor of a generated controller has the following signature PersonApiController(ObjectMapper objectMapper, HttpServletRequest request), but the developers of the generator may need to change it in the future. So the implementation would need to change too.

A third approach would be to forget completely about the generated PersonApiController, and just write a class that implements the PersonApi interface. That would be fine, but every time the code is generated you would need to delete the PersonApiController, otherwise Spring router will complain. Still manual work...

But with the delegation, the implementation code is completely safe. No need to manually delete stuff, no need to adapt in case of future changes. Also the class that implements PersonApiDelegate can be treated as an independent service, so you can inject / autowire into it whatever you need.

Acetic answered 20/2, 2021 at 20:37 Comment(2)
Thank you for your explanation. I found the delegate implementation a bit hard in testing and controller mocking (UnitTest). do you have any examples of how we test the controller code? Thanks.Mucoid
But you can set interfaceOnly to true to prevent the generation of a PersonController, there's no need to manually delete itRheinland
B
3

@BSL

I also stumbled about the problem of testing the controller, when it is generated via Delegate pattern: All my WebMvcTests returned a 404 error.

The reason for that is, if you only import the (in this case) PersonApiController (e.g. via a @WebMvcTest(PersonApiController.class) annotation, there is no information about the endpoints provided to Spring. The PersonApiController implements the PersonApiDelegate, but all endpoint information is only available on the PersonApi interface, which is not imported.

So you need to also import PersonApi additionally to your test:

@WebMvcTest(PersonApiController.class) // the controller you want to test
@Import(PersonApi.class) // the interface containing the endpoint path information
class PersonApiControllerTest {
   ...
}

Bicentennial answered 28/6, 2023 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.