Skip to content

Commit 7c2e892

Browse files
BAEL-8847: Generating HTTP Clients in Spring Boot from OpenAPI Spec (#18844)
* new maven execution. adds dependencies. adds jackson types dependencies * adds test * final version changes * set main clas to spring boot plugin
1 parent d45b2dc commit 7c2e892

File tree

6 files changed

+197
-1
lines changed

6 files changed

+197
-1
lines changed

spring-boot-modules/spring-boot-openapi/pom.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<version>${openapi-generator.version}</version>
6161
<executions>
6262
<execution>
63+
<id>generate-quotes-api</id>
6364
<goals>
6465
<goal>generate</goal>
6566
</goals>
@@ -80,13 +81,40 @@
8081
<modelPackage>com.baeldung.tutorials.openapi.quotes.api.model</modelPackage>
8182
<documentationProvider>source</documentationProvider>
8283
</configOptions>
84+
<generateApiTests>false</generateApiTests>
85+
<generateModelTests>false</generateModelTests>
86+
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
87+
</configuration>
88+
</execution>
89+
<execution>
90+
<id>generate-weather-api</id>
91+
<goals>
92+
<goal>generate</goal>
93+
</goals>
94+
<configuration>
95+
<inputSpec>${project.basedir}/src/main/resources/api/weatherapi.yaml</inputSpec>
96+
<generatorName>spring</generatorName>
97+
<configOptions>
98+
<openApiNullable>false</openApiNullable>
99+
<useJakartaEe>false</useJakartaEe>
100+
<annotationLibrary>none</annotationLibrary>
101+
<documentationProvider>none</documentationProvider>
102+
<apiPackage>com.baeldung.tutorials.openapi.generatehttpclients.api</apiPackage>
103+
<modelPackage>com.baeldung.tutorials.openapi.generatehttpclients.api.model</modelPackage>
104+
</configOptions>
105+
<generateApiTests>false</generateApiTests>
106+
<generateModelTests>false</generateModelTests>
107+
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
83108
</configuration>
84109
</execution>
85110
</executions>
86111
</plugin>
87112
<plugin>
88113
<groupId>org.springframework.boot</groupId>
89114
<artifactId>spring-boot-maven-plugin</artifactId>
115+
<configuration>
116+
<mainClass>com.baeldung.tutorials.openapi.generatehttpclients.GenerateHttpClientSpringApplication</mainClass>
117+
</configuration>
90118
</plugin>
91119
</plugins>
92120
</build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.tutorials.openapi.generatehttpclients;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class GenerateHttpClientSpringApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(GenerateHttpClientSpringApplication.class, args);
11+
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.baeldung.tutorials.openapi.generatehttpclients.service;
2+
3+
import org.springframework.stereotype.Service;
4+
5+
import com.baeldung.tutorials.openapi.generatehttpclients.api.WeatherApi;
6+
import com.baeldung.tutorials.openapi.generatehttpclients.api.model.WeatherResponse;
7+
8+
@Service
9+
public class GetWeatherService {
10+
11+
private final WeatherApi weatherApi;
12+
13+
public GetWeatherService(WeatherApi weatherApi) {
14+
this.weatherApi = weatherApi;
15+
}
16+
17+
public WeatherResponse getCurrentWeather(String city, String units) {
18+
var response = weatherApi.getCurrentWeather(city, units);
19+
20+
if (response.getStatusCodeValue() < 399) {
21+
return response.getBody();
22+
}
23+
24+
throw new RuntimeException("Failed to get current weather for " + city);
25+
}
26+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Current Weather API
4+
description: |
5+
Get real-time weather information for cities worldwide.
6+
version: 1.0.0
7+
8+
paths:
9+
/weather:
10+
get:
11+
summary: Get current weather data
12+
description: Retrieve current weather information for a specified city
13+
operationId: getCurrentWeather
14+
parameters:
15+
- name: city
16+
in: query
17+
required: true
18+
schema:
19+
type: string
20+
- name: units
21+
in: query
22+
required: false
23+
schema:
24+
type: string
25+
enum: [ celsius, fahrenheit ]
26+
default: celsius
27+
responses:
28+
'200':
29+
description: Successful weather data retrieval
30+
content:
31+
application/json:
32+
schema:
33+
$ref: '#/components/schemas/WeatherResponse'
34+
'404':
35+
description: City not found
36+
content:
37+
application/json:
38+
schema:
39+
$ref: '#/components/schemas/ErrorResponse'
40+
41+
components:
42+
schemas:
43+
WeatherResponse:
44+
type: object
45+
required:
46+
- location
47+
properties:
48+
current:
49+
type: object
50+
required:
51+
- temperature
52+
- units
53+
properties:
54+
temperature:
55+
type: number
56+
format: double
57+
units:
58+
type: string
59+
enum: [ celsius, fahrenheit ]
60+
timestamp:
61+
type: string
62+
format: date-time
63+
64+
ErrorResponse:
65+
type: object
66+
required:
67+
- code
68+
- message
69+
properties:
70+
code:
71+
type: string
72+
message:
73+
type: string

spring-boot-modules/spring-boot-openapi/src/main/resources/application.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
logging:
33
level:
44
root: INFO
5-
org.springframework: INFO
5+
org.springframework: INFO
6+
7+
openapi:
8+
currentWeather:
9+
base-path: https://localhost:8080
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.baeldung.tutorials.openapi.generatehttpclients;
2+
3+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
import static org.mockito.Mockito.when;
6+
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.extension.ExtendWith;
10+
import org.mockito.Mock;
11+
import org.mockito.junit.jupiter.MockitoExtension;
12+
import org.springframework.http.HttpStatus;
13+
import org.springframework.http.ResponseEntity;
14+
15+
import com.baeldung.tutorials.openapi.generatehttpclients.api.WeatherApi;
16+
import com.baeldung.tutorials.openapi.generatehttpclients.api.model.WeatherResponse;
17+
import com.baeldung.tutorials.openapi.generatehttpclients.api.model.WeatherResponseCurrent;
18+
import com.baeldung.tutorials.openapi.generatehttpclients.service.GetWeatherService;
19+
20+
@ExtendWith(MockitoExtension.class)
21+
class WeatherApiUnitTest {
22+
23+
private GetWeatherService weatherService;
24+
25+
@Mock
26+
private WeatherApi weatherApi;
27+
28+
@BeforeEach
29+
void setUp() {
30+
weatherService = new GetWeatherService(weatherApi);
31+
}
32+
33+
@Test
34+
void givenOkStatus_whenCallingWeatherApi_thenReturnCurrentWeather() {
35+
when(weatherApi.getCurrentWeather("London", "celsius")).thenReturn(
36+
new ResponseEntity<>(new WeatherResponse().current(new WeatherResponseCurrent(455d, WeatherResponseCurrent.UnitsEnum.CELSIUS)), HttpStatus.OK));
37+
38+
var weather = weatherService.getCurrentWeather("London", "celsius");
39+
40+
assertThat(weather.getCurrent()
41+
.getTemperature()).isEqualTo(455d);
42+
assertThat(weather.getCurrent()
43+
.getUnits()).isEqualTo(WeatherResponseCurrent.UnitsEnum.CELSIUS);
44+
}
45+
46+
@Test
47+
void givenBadRequestStatus_whenCallingWeatherApi_thenReturnError() {
48+
when(weatherApi.getCurrentWeather("London", "celsius")).thenReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
49+
50+
assertThrows(RuntimeException.class, () -> weatherService.getCurrentWeather("London", "celsius"));
51+
}
52+
}

0 commit comments

Comments
 (0)