How to Create a Spring-Boot REST Server Using OpenAPITools
Asked Answered
H

1

1

I created a Spring Boot server using the tools at swagger.io, which I'm now porting to OpenAPITools. But I can't find the equivalent generator. I tried setting the generaterName to spring, but it creates a somewhat different application. First, it uses a WebMvcConfigurer Bean, even though it's not an MVC application. Second, the generated Controller and API don't give me an ObjectMapper. Third, instead of an HttpServletRequest, they give me a more ambiguous NativeWebRequest instance. Is there a matching generator for the spring REST generator at swagger.io? Am I doing something wrong?

Here's the openApiTools maven plugin from my pom.xml file:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <!-- RELEASE_VERSION -->
    <version>4.3.1</version>
    <!-- /RELEASE_VERSION -->
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <!-- Configuration properties taken from -->
                <!-- https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-maven-plugin/README.md -->
                <inputSpec>${project.basedir}/src/gen/java/main/pizzeria.yaml</inputSpec>
                <generatorName>spring</generatorName>
                <!-- <output>${project.basedir}</output>-->
                <!-- Defaults to ${project.build.directory}/generated-sources/openapi -->
                <apiPackage>com.dummy.pizzeria.api</apiPackage>
                <modelPackage>com.dummy.pizzeria.model</modelPackage>
                <invokerPackage>com.dummy.pizzeria</invokerPackage>
                <packageName>com.dummy.pizzeria.objects</packageName>
                <groupId>neptunedreams</groupId>
                <artifactId>pizzeria</artifactId>
                <library>spring-boot</library>
                <generateModelTests>false</generateModelTests>
                <!--<generateSupportingFiles>false</generateSupportingFiles>-->
                <configOptions>
                    <!-- configOptions are specific to the spring generator. These are taken from -->
                    <!-- https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/spring.md -->
                    <sourceFolder>gen</sourceFolder>
                    <bigDecimalAsString>true</bigDecimalAsString>
                    <dateLibrary>java8</dateLibrary> <!-- Default-->
                    <performBeanValidation>true</performBeanValidation>
                    <useBeanValidation>true</useBeanValidation>
                    <skipDefaultInterface>true</skipDefaultInterface>
                    <library>spring-boot</library>
                    <interfaceOnly>false</interfaceOnly>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
Hbeam answered 11/10, 2020 at 12:32 Comment(0)
W
0

I know you asked this same question on our Slack channel the day before you posted here, but you never replied to my response so I'm duplicating it here.

Spring should only be outputting the MVC file if you’ve specified the library as spring-mvc. Our default library is spring-boot for these generators. I’d recommend checking your pom and any external config (specified via configFile or maven properties) to see if you have some conflicting configuration.

You can compare with the config file for this sample in our repo.

We support the libraries:

  • spring-mvc
  • spring-boot
  • spring-cloud

I did run example you posted above and see spring boot output. However, I see that you're not defining the output directory (it's commented out in your example) so this would just generate into target/generated-sources. I'm assuming you maybe could have tried spring-mvc at one point, then began generating into target unexpectedly.

If you want to generate into your project structure you'll always need to specify output. For example, to write out to ./my-springboot, you'd add:

<output>${project.basedir}/my-springboot</output>

This outputs springboot code, as expected:

➜  examples git:(master) ✗ tree my-springboot
my-springboot
├── README.md
├── pom.xml
└── src
    └── main
        ├── java
        │   ├── com
        │   │   └── dummy
        │   │       └── pizzeria
        │   │           ├── OpenAPI2SpringBoot.java
        │   │           ├── RFC3339DateFormat.java
        │   │           ├── api
        │   │           │   ├── ApiUtil.java
        │   │           │   ├── PetApi.java
        │   │           │   ├── PetApiController.java
        │   │           │   ├── StoreApi.java
        │   │           │   ├── StoreApiController.java
        │   │           │   ├── UserApi.java
        │   │           │   └── UserApiController.java
        │   │           └── model
        │   │               ├── Category.java
        │   │               ├── ModelApiResponse.java
        │   │               ├── Order.java
        │   │               ├── Pet.java
        │   │               ├── Tag.java
        │   │               └── User.java
        │   └── org
        │       └── openapitools
        │           └── configuration
        │               ├── HomeController.java
        │               └── OpenAPIDocumentationConfig.java
        └── resources
            └── application.properties

12 directories, 20 files

If you want to generate into a sub-module and you have some complex logic aside from excluding supportingFiles, which I mention because you've commented this out in your example, you can define an external ignore file.

Suppose you don't want to modify the pom, properties, README, and any implementation files you have created (or plan to)… create a file in your project root called my-springboot.ignore:

# This file works like .gitignore, patterns here won't be written or overwritten.
# Test files are never overwritten.
**/pom.xml
**/application.properties
**/README.md
**/*Impl.java

I'd also recommend updating to version 5.0.0-beta2 of the generator.

Full code

Here's the full plugin node I used to test locally, including all recommendations above.

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>5.0.0-beta2</version>
    <executions>
    <execution>
        <goals>
            <goal>generate</goal>
        </goals>
        <configuration>
            <ignoreFileOverride>${project.basedir}/my-springboot.ignores</ignoreFileOverride>
            <inputSpec>${project.basedir}/openapi.yaml</inputSpec>
            <generatorName>spring</generatorName>
            <apiPackage>com.dummy.pizzeria.api</apiPackage>
            <modelPackage>com.dummy.pizzeria.model</modelPackage>
            <invokerPackage>com.dummy.pizzeria</invokerPackage>
            <packageName>com.dummy.pizzeria.objects</packageName>
            <groupId>neptunedreams</groupId>
            <artifactId>pizzeria</artifactId>
            <library>spring-boot</library>
            <generateModelTests>false</generateModelTests>
            <output>${project.basedir}/my-springboot</output>
            <configOptions>
                <bigDecimalAsString>true</bigDecimalAsString>
                <dateLibrary>java8</dateLibrary>
                <performBeanValidation>true</performBeanValidation>
                <useBeanValidation>true</useBeanValidation>
                <skipDefaultInterface>true</skipDefaultInterface>
                <library>spring-boot</library>
                <interfaceOnly>false</interfaceOnly>
            </configOptions>
        </configuration>
    </execution>
    </executions>
</plugin>
Witkin answered 15/10, 2020 at 2:6 Comment(9)
I've modified the pom.xml file to match what you have here, but when I generate the code, I still see the WebMvcConfigurer in the generated OpenAPI2SpringBoot.java file. I shouldn't see that if I'm specifying the spring-boot library. Why do I get this? I'm also seeing other things I don't like. In the generated controllers, I see a NativeWebRequest instance instead of an HttpServletRequest.Hbeam
afaik, WebMvcConfigurer is the only way in Spring Boot to configure CORS. It's included with spring-boot-starter-web, so I don't follow the concern about it's included there. I can't speak for the design decision that the spring generator's maintainers made for using NativeWebRequest over HttpServletRequest. I'd suggest opening an issue or pinging in Slack. I've only personally ever seen HttpServletRequest used in Spring Classic when using tomcat. It's likely the change was made to allow users to easily choose between Tomcat (default) and Jetty.Witkin
My understanding is that CORS is for web applications, so I'm still not sure why I'm seeing a WebMvcConfigurer in a Spring-Boot REST server application.Hbeam
You may have CSRF and CORS confused. CORS allows sharing of resources (the "R" in REST) between different origins (hosts, URLs). CSRF is reliant on cookies and only really relevant to browser based applications.Witkin
I'm still not clear how to generate code that doesn't use WebMvcConfigurer.Hbeam
The trouble seems to be that the generator now assumes any Spring-boot application is a web application. This is a bad assumption. Spring Boot is more generic, and is also intended for RESTful services with no front end. I used to be able to use swagger to build an api for this by specifying spring-boot for my library. But now, when I still get an mvc application. If I wanted mvc, I would have specified the spring-mvc library. How do I get a spring-boot build that doesn't use mvc? Also, RESTful services don't use CORS or CSRF protection.Hbeam
You're misunderstanding what CORS is, and obviously need to read up on API security if you truly believe CORS has no place in an API. A quick internet search for "cors api security springboot" could easily answer your questions. The package and annotations needed to enable cors just happen to live in MVC packages... that doesn't create an MVC application or a web frontend.Witkin
I see. Here's what I read about CORS on Wikipedia: "Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos…" This makes me wonder if you're using a different term with the same acronym. (This would be very ironic, since acronyms are not what CORS actually shares.) Are we using the same definition?Hbeam
I'm seeing a lot of examples of how to set up Spring Security that assume I have a login page. So I've been having trouble adapting them to the needs of my service. This has made me very wary of any libraries that look like they're intended for browser apps.Hbeam

© 2022 - 2024 — McMap. All rights reserved.