def appVersion = getAppVersion()
group = 'org.onap'
version = appVersion
-sourceCompatibility = '17'
-targetCompatibility = '17'
springBoot {
buildInfo {
package org.onap.portalng.preferences.configuration;
import org.onap.portalng.preferences.util.Logger;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.reactive.ServerWebExchangeContextFilter;
import org.springframework.web.server.ServerWebExchange;
@Component
public class LogInterceptor implements WebFilter {
- public static final String EXCHANGE_CONTEXT_ATTRIBUTE =
- ServerWebExchangeContextFilter.class.getName() + ".EXCHANGE_CONTEXT";
+ public static final String EXCHANGE_CONTEXT_ATTRIBUTE = ServerWebExchangeContextFilter.class.getName()
+ + ".EXCHANGE_CONTEXT";
- public static final String X_REQUEST_ID = "X-Request-Id";
+ @Value("${logger.traceIdHeaderName}")
+ public static String X_REQUEST_ID;
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (xRequestIdList != null && !xRequestIdList.isEmpty()) {
String xRequestId = xRequestIdList.get(0);
Logger.requestLog(
- xRequestId, exchange.getRequest().getMethod(), exchange.getRequest().getURI());
+ exchange.getRequest().getMethod(), exchange.getRequest().getURI());
exchange.getResponse().getHeaders().add(X_REQUEST_ID, xRequestId);
exchange.getResponse().beforeCommit(() -> {
- Logger.responseLog(xRequestId,exchange.getResponse().getStatusCode());
+ Logger.responseLog(exchange.getResponse().getStatusCode());
return Mono.empty();
});
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Bean
public SecurityWebFilterChain springSecurityWebFilterChain(ServerHttpSecurity http) {
- return http.httpBasic(basic -> basic.disable()
- .formLogin(login -> login.disable()
- .csrf(csrf -> csrf.disable()
- .cors())))
- .authorizeExchange(exchange -> exchange
- .pathMatchers(HttpMethod.GET, "/actuator/**").permitAll()
- .anyExchange().authenticated())
- .oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::jwt)
- .build();
+ return http
+ .httpBasic(basic -> basic.disable())
+ .formLogin(login -> login.disable())
+ .csrf(csrf -> csrf.disable())
+ .cors(Customizer.withDefaults())
+ .authorizeExchange(exchange -> exchange
+ .pathMatchers(HttpMethod.GET, "/actuator/**").permitAll()
+ .anyExchange().authenticated())
+ .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
+ .build();
}
}
*/
package org.onap.portalng.preferences.controller;
+
import org.onap.portalng.preferences.exception.ProblemException;
import org.onap.portalng.preferences.openapi.api.PreferencesApi;
-import org.onap.portalng.preferences.openapi.model.Preferences;
+import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
import org.onap.portalng.preferences.services.PreferencesService;
import org.onap.portalng.preferences.util.IdTokenExchange;
import org.onap.portalng.preferences.util.Logger;
@RestController
public class PreferencesController implements PreferencesApi {
-
private final PreferencesService preferencesService;
- public PreferencesController(PreferencesService getPreferences){
+ public PreferencesController(PreferencesService getPreferences) {
this.preferencesService = getPreferences;
}
@Override
- public Mono<ResponseEntity<Preferences>> getPreferences(String xRequestId, ServerWebExchange exchange) {
+ public Mono<ResponseEntity<PreferencesApiDto>> getPreferences(ServerWebExchange exchange) {
return IdTokenExchange
- .extractUserId(exchange)
- .flatMap(userid ->
- preferencesService.getPreferences(userid)
- .map(ResponseEntity::ok))
- .onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog(xRequestId,"user preferences", null, "preferences" );
- return Mono.error(ex);
- })
- .onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
+ .extractUserId(exchange)
+ .flatMap(userid -> preferencesService.getPreferences(userid)
+ .map(ResponseEntity::ok))
+ .onErrorResume(ProblemException.class, ex -> {
+ Logger.errorLog("user preferences", null, "preferences");
+ return Mono.error(ex);
+ })
+ .onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
}
@Override
- public Mono<ResponseEntity<Preferences>> savePreferences(String xRequestId, Mono<Preferences> preferences,
- ServerWebExchange exchange) {
- return IdTokenExchange
- .extractUserId(exchange)
- .flatMap(userid ->
- preferences
- .flatMap( pref ->
- preferencesService
- .savePreferences(xRequestId, userid, pref)))
- .map( ResponseEntity::ok)
+ public Mono<ResponseEntity<PreferencesApiDto>> savePreferences(Mono<PreferencesApiDto> preferences,
+ ServerWebExchange exchange) {
+ return IdTokenExchange
+ .extractUserId(exchange)
+ .flatMap(userid -> preferences
+ .flatMap(pref -> preferencesService
+ .savePreferences(userid, pref)))
+ .map(ResponseEntity::ok)
.onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog(xRequestId,"user preferences", null, "preferences" );
+ Logger.errorLog("user preferences", null, "preferences");
return Mono.error(ex);
})
- .onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
+ .onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
}
@Override
- public Mono<ResponseEntity<Preferences>> updatePreferences(String xRequestId, Mono<Preferences> preferences, ServerWebExchange exchange) {
- return savePreferences(xRequestId, preferences, exchange);
+ public Mono<ResponseEntity<PreferencesApiDto>> updatePreferences(Mono<PreferencesApiDto> preferences,
+ ServerWebExchange exchange) {
+ return savePreferences(preferences, exchange);
}
}
import org.onap.portalng.preferences.entities.PreferencesDto;
import org.onap.portalng.preferences.exception.ProblemException;
-import org.onap.portalng.preferences.openapi.model.Preferences;
+import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
import org.onap.portalng.preferences.repository.PreferencesRepository;
import org.onap.portalng.preferences.util.Logger;
import org.springframework.beans.factory.annotation.Autowired;
private final ObjectMapper objectMapper;
- public Mono<Preferences> getPreferences(String userId){
+ public Mono<PreferencesApiDto> getPreferences(String userId) {
return Mono.just(repository
- .findById(userId)
- .orElse(defaultPreferences()))
- .map(this::toPreferences);
+ .findById(userId)
+ .orElse(defaultPreferences()))
+ .map(this::toPreferences);
}
- public Mono<Preferences> savePreferences( String xRequestId, String userId, Preferences preferences){
+ public Mono<PreferencesApiDto> savePreferences(String userId, PreferencesApiDto preferences) {
var preferencesDto = new PreferencesDto();
preferencesDto.setUserId(userId);
preferencesDto.setProperties(objectMapper.valueToTree(preferences.getProperties()));
return Mono.just(repository.save(preferencesDto))
- .map(this::toPreferences)
- .onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog(xRequestId,"user prefrences", userId, "preferences" );
- return Mono.error(ex);
- });
+ .map(this::toPreferences)
+ .onErrorResume(ProblemException.class, ex -> {
+ Logger.errorLog("user prefrences", userId, "preferences");
+ return Mono.error(ex);
+ });
}
- private Preferences toPreferences(PreferencesDto preferencesDto) {
- var preferences = new Preferences();
+ private PreferencesApiDto toPreferences(PreferencesDto preferencesDto) {
+ var preferences = new PreferencesApiDto();
preferences.setProperties(preferencesDto.getProperties());
return preferences;
}
* Get a Preferences object that is initialised with an empty string.
* This is a) for convenience to not handle 404 on the consuming side and
* b) for security reasons
+ *
* @return PreferencesDto
*/
private PreferencesDto defaultPreferences() {
@Slf4j
public class Logger {
- private Logger(){}
+ private Logger() {
+ }
- public static void requestLog(String xRequestId, HttpMethod methode, URI path) {
- log.info("Preferences - request - X-Request-Id {} {} {}", xRequestId, methode, path);
+ public static void requestLog(HttpMethod methode, URI path) {
+ log.info("Preferences - request - {} {}", methode, path);
}
- public static void responseLog(String xRequestId, HttpStatusCode httpStatusCode) {
- log.info("Preferences - response - X-Request-Id {} {}", xRequestId, httpStatusCode);
+ public static void responseLog(HttpStatusCode httpStatusCode) {
+ log.info("Preferences - response - {}", httpStatusCode);
}
- public static void errorLog(String xRequestId, String msg, String id, String app) {
+ public static void errorLog(String msg, String id, String app) {
log.info(
- "Preferences - error - X-Request-Id {} {} {} not found in {}", xRequestId, msg, id, app);
+ "Preferences - error - {} {} not found in {}", msg, id, app);
}
public static void errorLog(
- String xRequestId, String msg, String id, String app, String errorDetails) {
+ String msg, String id, String app, String errorDetails) {
log.info(
- "Preferences - error - X-Request-Id {} {} {} not found in {} error message: {}",
- xRequestId,
+ "Preferences - error - {} {} not found in {} error message: {}",
msg,
id,
app,
endpoint: http://${COLLECTOR_HOST}:${COLLECTOR_PORT}/api/v2/spans
logger:
- traceIdHeaderName: "X-Request-Id"
+ traceIdHeaderName: ${TRACE_ID_HEADER_NAME}
enabled: true
excludePaths:
- "/actuator/**"
import org.junit.jupiter.api.Test;
import org.onap.portalng.preferences.BaseIntegrationTest;
-import org.onap.portalng.preferences.openapi.model.Preferences;
+import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
import org.onap.portalng.preferences.services.PreferencesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import io.restassured.http.ContentType;
-import io.restassured.http.Header;
class PreferencesControllerIntegrationTest extends BaseIntegrationTest {
- protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57";
-
- @Autowired
- PreferencesService preferencesService;
-
- @Test
- void thatUserPreferencesCanBeRetrieved() {
- // First save a user preference before a GET can run
- Preferences expectedResponse = new Preferences()
- .properties("{\"properties\": {\"dashboard\": {\"key1:\": \"value2\"}, \"appStarter\": \"value1\"}}");
- preferencesService
- .savePreferences(X_REQUEST_ID,"test-user", expectedResponse)
- .block();
-
- Preferences actualResponse = requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(Preferences.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanNotBeRetrieved() {
- unauthenticatedRequestSpecification()
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.UNAUTHORIZED.value());
- }
-
- @Test
- void thatUserPreferencesCanBeSaved() {
- Preferences expectedResponse = new Preferences()
- .properties("""
- {
- "properties": { "appStarter": "value1",
- "dashboard": {"key1:" : "value2"}
- }\s
- }\
- """);
- Preferences actualResponse = requestSpecification()
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .body(expectedResponse)
- .when()
- .post("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(Preferences.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanBeUpdated() {
- // First save a user preference before a GET can run
- Preferences initialPreferences = new Preferences()
- .properties("""
- {
- "properties": { "appStarter": "value1",
- "dashboard": {"key1:" : "value2"}
- }\s
- }\
- """);
- preferencesService
- .savePreferences(X_REQUEST_ID,"test-user", initialPreferences)
- .block();
-
- Preferences expectedResponse = new Preferences()
- .properties("""
- {
- "properties": { "appStarter": "value3",
- "dashboard": {"key2:" : "value4"}
- }\s
- }\
- """);
- Preferences actualResponse = requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .body(expectedResponse)
- .when()
- .put("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(Preferences.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanNotBeFound() {
-
- Preferences actualResponse = requestSpecification("test-canNotBeFound")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(Preferences.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isNull();
- }
-
- @Test
- void thatUserPreferencesHasXRequestIdHeader() {
-
- String actualResponse = requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .header(new Header("X-Request-Id", X_REQUEST_ID))
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .header("X-Request-Id");
-
- assertThat(actualResponse).isNotNull().isEqualTo(X_REQUEST_ID);
- }
-
- @Test
- void thatUserPreferencesHasNoXRequestIdHeader() {
-
- requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.BAD_REQUEST.value());
-
-
- }
+ @Autowired
+ PreferencesService preferencesService;
+
+ @Test
+ void thatUserPreferencesCanBeRetrieved() {
+ // First save a user preference before a GET can run
+ PreferencesApiDto expectedResponse = new PreferencesApiDto()
+ .properties("{\"properties\": {\"dashboard\": {\"key1:\": \"value2\"}, \"appStarter\": \"value1\"}}");
+ preferencesService
+ .savePreferences("test-user", expectedResponse)
+ .block();
+
+ PreferencesApiDto actualResponse = requestSpecification("test-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .when()
+ .get("/v1/preferences")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(PreferencesApiDto.class);
+
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
+ }
+
+ @Test
+ void thatUserPreferencesCanNotBeRetrieved() {
+ unauthenticatedRequestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(ContentType.JSON)
+ .when()
+ .get("/v1/preferences")
+ .then()
+ .statusCode(HttpStatus.UNAUTHORIZED.value());
+ }
+
+ @Test
+ void thatUserPreferencesCanBeSaved() {
+ PreferencesApiDto expectedResponse = new PreferencesApiDto()
+ .properties("""
+ {
+ "properties": { "appStarter": "value1",
+ "dashboard": {"key1:" : "value2"}
+ }\s
+ }\
+ """);
+ PreferencesApiDto actualResponse = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(ContentType.JSON)
+ .body(expectedResponse)
+ .when()
+ .post("/v1/preferences")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(PreferencesApiDto.class);
+
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
+ }
+
+ @Test
+ void thatUserPreferencesCanBeUpdated() {
+ // First save a user preference before a GET can run
+ PreferencesApiDto initialPreferences = new PreferencesApiDto()
+ .properties("""
+ {
+ "properties": { "appStarter": "value1",
+ "dashboard": {"key1:" : "value2"}
+ }\s
+ }\
+ """);
+ preferencesService
+ .savePreferences("test-user", initialPreferences)
+ .block();
+
+ PreferencesApiDto expectedResponse = new PreferencesApiDto()
+ .properties("""
+ {
+ "properties": { "appStarter": "value3",
+ "dashboard": {"key2:" : "value4"}
+ }\s
+ }\
+ """);
+ PreferencesApiDto actualResponse = requestSpecification("test-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(ContentType.JSON)
+ .body(expectedResponse)
+ .when()
+ .put("/v1/preferences")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(PreferencesApiDto.class);
+
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
+ }
+
+ @Test
+ void thatUserPreferencesCanNotBeFound() {
+
+ PreferencesApiDto actualResponse = requestSpecification("test-canNotBeFound")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .when()
+ .get("/v1/preferences")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(PreferencesApiDto.class);
+
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getProperties()).isNull();
+ }
}
port: 9001
address: 0.0.0.0
-de:
- flapdoodle:
- mongodb:
- embedded:
- version: 5.0.15
-
spring:
jackson:
serialization:
enabled: true
logger:
- traceIdHeaderName: "X-Request-Id"
+ traceIdHeaderName: ${TRACE_ID_HEADER_NAME}
enabled: true
excludePaths:
- "/actuator/**"
repositories {
mavenCentral()
}
-}
\ No newline at end of file
+}
Content-Type: application/json
Authorization: Bearer {{access_token}}
X-Auth-Identity: Bearer {{id_token}}
-X-Request-Id: {{$uuid}}
+x-b3-spanid: {{$uuid}}
{
"properties": {
Accept: application/json
Authorization: Bearer {{access_token}}
X-Auth-Identity: Bearer {{id_token}}
-X-Request-Id: {{$uuid}}
+x-b3-spanid: {{$uuid}}
###
plugins {
id 'java'
- id 'idea'
id 'org.openapi.generator'
}
-repositories {
- mavenCentral()
-}
-
dependencies {
- compileOnly 'org.openapitools:openapi-generator:7.0.0-beta'
- compileOnly 'org.springframework.boot:spring-boot-starter-webflux:3.4.5'
- compileOnly 'jakarta.validation:jakarta.validation-api:3.0.2'
-
- constraints {
- implementation('io.swagger.core.v3:swagger-annotations:2.2.5') {
- because 'there is a dependency conflict between swagger-parser versions 2 and 3 (https://github.com/OpenAPITools/openapi-generator/issues/14901)'
- }
- }
+ compileOnly 'io.swagger.core.v3:swagger-annotations:2.2.34'
+ compileOnly 'org.springframework.boot:spring-boot-starter-webflux:3.5.4'
+ compileOnly 'jakarta.validation:jakarta.validation-api:3.1.1'
}
// https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-gradle-plugin/README.adoc
invokerPackage = "org.onap.portalng.preferences.openapi"
apiPackage = "org.onap.portalng.preferences.openapi.api"
modelPackage = "org.onap.portalng.preferences.openapi.model"
+ modelNameSuffix = "ApiDto"
}
compileJava {
openapi: 3.0.2
info:
- title: Config API
- version: '1.0'
+ title: Portal NG Preferences
+ version: '1.1'
+ description: Portal NG Preferences
+ contact:
+ name: ONAP
servers:
- - url: 'http://localhost:9001/'
+ - url: http://localhost:9001
+tags:
+ - name: preferences
paths:
/v1/preferences:
get:
description: Returns user preferences
summary: Get user preferences
operationId: getPreferences
- parameters:
- - $ref: '#/components/parameters/XRequestIdHeader'
tags:
- preferences
responses:
description: Updates user preferences
summary: Update user preferences
operationId: updatePreferences
- parameters:
- - $ref: '#/components/parameters/XRequestIdHeader'
tags:
- preferences
requestBody:
description: Save user preferences
summary: Save user preferences
operationId: savePreferences
- parameters:
- - $ref: '#/components/parameters/XRequestIdHeader'
tags:
- preferences
requestBody:
'502':
$ref: '#/components/responses/BadGateway'
components:
- parameters:
- XRequestIdHeader:
- name: X-Request-Id
- in: header
- description: The unique identifier of the request
- required: true
- schema:
- type: string
schemas:
Preferences:
type: object
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
Unauthorized:
description: '401: Unauthorized'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
Forbidden:
description: '403: Forbidden'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
NotFound:
description: '404: Not Found'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
NotAllowed:
description: '405: Method Not Allowed'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
Conflict:
description: '409: Conflict'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
InternalServerError:
description: Internal Server Error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response
BadGateway:
description: Bad Gateway
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
- headers:
- X-Request-Id:
- schema:
- type: string
- description: A <uuid4> in each response