Override an existing endpoint
Goal: change how one HTTP endpoint behaves at the web layer — here, hide the internal
stripePriceId from the GET /events/{id} response — without touching the use cases.
- Seam: the abstract
EventControllerbase (@ModelCityExtensionPoint). - City files: one
@RestController. - Applies to: both topologies.
Why it works
Controllers are exposed as an abstract base carrying @RestController, the class-level
@RequestMapping("/events") and the endpoint methods, generic over the DTOs. A city
extends it, @Overrides the methods it wants, and the concrete subclass inherits the request
mappings. As soon as such a bean exists, DefaultEventController backs off — so there is never
a duplicate /events mapping.
Recipe
Extend the base, bind the platform DTOs, and override the one method. The overriding method
keeps the same signature (that is how it inherits the mapping); Spring MVC inherits the
@PathVariable / @RequestParam binding from the base method, so you don't re-declare them.
// com.modelcity.leisure.events.controller.MyEventController
@RestController
public class MyEventController extends EventController<EventDto, EventSummaryDto, EventRequestDto> {
public MyEventController(
GetEventsUseCase<EventSummaryDto> getEventsUseCase,
GetEventUseCase<EventDto> getEventUseCase,
GetEventForEditUseCase<EventDto> getEventForEditUseCase,
CreateEventUseCase<EventDto, EventRequestDto> createEventUseCase,
UpdateEventUseCase<EventDto, EventRequestDto> updateEventUseCase,
DeleteEventUseCase deleteEventUseCase) {
super(getEventsUseCase, getEventUseCase, getEventForEditUseCase,
createEventUseCase, updateEventUseCase, deleteEventUseCase);
}
@Override
public EventDto getEvent(Long id, String sub, String translations, Locale locale) {
EventDto dto = super.getEvent(id, sub, translations, locale);
dto.setStripePriceId(null); // don't expose the Stripe price id
return dto;
}
}
The other endpoints (getEvents, createEvent, updateEvent, deleteEvent) are inherited
unchanged from EventController.
Notes
- Re-declare access annotations on any protected endpoint you override.
@ModelCityAccess.*is read by an aspect from the invoked method; method annotations are not inherited, so an override that omits them turns the endpoint open.getEventis public (no annotation), so nothing to re-declare here — but see Change an endpoint's role restriction. - The generated project ships exactly this pattern as
ExampleCityEventController(delete or adapt it). - To change business logic rather than HTTP shaping, override the use case instead — it is reused by every topology and every controller.
Verify
curl /events/{id} no longer contains stripePriceId; every other event endpoint is
unchanged, and the startup log shows DefaultEventController … disabled.