Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions src/main/java/no/entur/mummu/config/SwaggerConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.servers.Server;
import org.springdoc.core.customizers.SpringDocCustomizers;
import io.swagger.v3.oas.models.tags.Tag;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -46,7 +48,38 @@ public SwaggerConfiguration() {
public OpenAPI customOpenAPI() {
Server server = new Server();
server.setUrl(hostUrl);
return new OpenAPI().servers(List.of(server));
return new OpenAPI()
.servers(List.of(server))
.info(new Info()
.title("Stop Place Register")
.version("1.0.0")
.description("The Stop Place Register provides access to public transportation infrastructure data across Norway, including stop places, quays, parkings, and related NeTEx entities. This API enables developers to query stop place information with details on location, accessibility features, transport modes, fare zones, and hierarchical relationships. Ideal for journey planning applications, transportation analysis, mobility services, and public transit integrations.")
.contact(new Contact()
.name("Entur API Support")
.url("https://developer.entur.org")))
.tags(List.of(
new Tag()
.name("Stop Places")
.description("Query and retrieve stop place information including stations, terminals, bus stops, and ferry ports. Includes filtering by transport mode, location, and other attributes."),
new Tag()
.name("Quays")
.description("Access detailed information about quays (platforms, boarding positions) and their relationship to stop places. Query by ID or retrieve version history."),
new Tag()
.name("Scheduled Stop Points")
.description("Retrieve scheduled stop points used in route planning and timetables, and their mappings to physical stop places."),
new Tag()
.name("Fare Zones")
.description("Access fare zone definitions and boundaries used for ticket pricing calculations. Query by authority or specific zones."),
new Tag()
.name("Parking")
.description("Find parking facilities associated with stop places, including capacity, pricing, and accessibility information."),
new Tag()
.name("Geographic Areas")
.description("Query topographic places (municipalities, counties, countries) and tariff zones for geographic and administrative boundaries."),
new Tag()
.name("Groupings")
.description("Access logical groupings of stop places and fare zones for organizational and operational purposes.")
));
}

@Bean
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/no/entur/mummu/resources/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package no.entur.mummu.resources;

import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Map;

@Schema(description = "Error response returned when a request fails")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ErrorResponse {

@Schema(description = "Machine-readable error code", example = "RESOURCE_NOT_FOUND")
private String errorCode;

@Schema(description = "Human-readable error message", example = "Resource not found")
private String message;

@Schema(description = "Additional error context")
private Map<String, Object> details;

public ErrorResponse() {}

public ErrorResponse(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}

public ErrorResponse(String errorCode, String message, Map<String, Object> details) {
this.errorCode = errorCode;
this.message = message;
this.details = details;
}

// Getters and setters
public String getErrorCode() {
return errorCode;
}

public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public Map<String, Object> getDetails() {
return details;
}

public void setDetails(Map<String, Object> details) {
this.details = details;
}
}
72 changes: 72 additions & 0 deletions src/main/java/no/entur/mummu/resources/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package no.entur.mummu.resources;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
private static final String INVALID_PARAMETER = "INVALID_PARAMETER";

@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFoundException(NotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"RESOURCE_NOT_FOUND",
ex.getMessage()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}

@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ErrorResponse> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
ErrorResponse error = new ErrorResponse(
INVALID_PARAMETER,
String.format("Invalid value '%s' for parameter '%s'", ex.getValue(), ex.getName()),
Map.of("parameter", ex.getName(), "providedValue", String.valueOf(ex.getValue()))
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
if (fieldError != null) {
String parameterName = fieldError.getField();
Object rejectedValue = fieldError.getRejectedValue();
ErrorResponse error = new ErrorResponse(
INVALID_PARAMETER,
String.format("Invalid value '%s' for parameter '%s'", rejectedValue, parameterName),
Map.of("parameter", parameterName, "providedValue", String.valueOf(rejectedValue))
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
ErrorResponse error = new ErrorResponse(INVALID_PARAMETER, "Validation failed");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException ex) {
ErrorResponse error = new ErrorResponse(INVALID_PARAMETER, ex.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
logger.error("Unexpected error", ex);
ErrorResponse error = new ErrorResponse(
"INTERNAL_ERROR",
"An unexpected error occurred while processing your request"
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}
13 changes: 11 additions & 2 deletions src/main/java/no/entur/mummu/resources/NotFoundException.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "entity not found")
public class NotFoundException extends RuntimeException {}
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {

public NotFoundException() {
super("The requested resource was not found");
}

public NotFoundException(String message) {
super(message);
}
}
Loading