From e1a9e5f8fc16965470314abd9bcb28dc85dc094c Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Wed, 15 Apr 2026 12:37:42 +0200 Subject: [PATCH 1/3] refactor: update PetController base URL to `/api/pets` --- src/main/java/org/example/vet1177/controller/PetController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/example/vet1177/controller/PetController.java b/src/main/java/org/example/vet1177/controller/PetController.java index 99677543..67749540 100644 --- a/src/main/java/org/example/vet1177/controller/PetController.java +++ b/src/main/java/org/example/vet1177/controller/PetController.java @@ -16,7 +16,7 @@ import java.util.UUID; @RestController -@RequestMapping("/pets") +@RequestMapping("/api/pets") public class PetController { private static final Logger log = LoggerFactory.getLogger(PetController.class); From e345d24e39930fb3afdf9fd27ba770e1d93f12de Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Wed, 15 Apr 2026 12:38:16 +0200 Subject: [PATCH 2/3] test: update PetControllerTest URLs to match updated `/api/pets` base path --- .../vet1177/controller/PetControllerTest.java | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/src/test/java/org/example/vet1177/controller/PetControllerTest.java b/src/test/java/org/example/vet1177/controller/PetControllerTest.java index 32ae72b6..77ff2820 100644 --- a/src/test/java/org/example/vet1177/controller/PetControllerTest.java +++ b/src/test/java/org/example/vet1177/controller/PetControllerTest.java @@ -94,9 +94,9 @@ private RequestPostProcessor authenticatedAs(User user) { void createPet_shouldReturn200WithPetResponse() throws Exception { when(petService.createPet(any(), any(), any())).thenReturn(pet); - mockMvc.perform(post("/pets") + mockMvc.perform(post("/api/pets") .with(authenticatedAs(owner)) - .header("currentUserId", ownerId) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isOk()) @@ -108,9 +108,9 @@ void createPet_whenInvalidRequest_shouldReturn400() throws Exception { PetRequest request = validPetRequest(); request.setName(""); - mockMvc.perform(post("/pets") + mockMvc.perform(post("/api/pets") .with(authenticatedAs(owner)) - .header("currentUserId", ownerId) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isBadRequest()); @@ -121,9 +121,9 @@ void createPet_whenForbidden_shouldReturn403() throws Exception { when(petService.createPet(any(), any(), any())) .thenThrow(new ForbiddenException("Du kan inte lägga till ett djur")); - mockMvc.perform(post("/pets") + mockMvc.perform(post("/api/pets") .with(authenticatedAs(vet)) - .header("currentUserId", UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isForbidden()); @@ -134,9 +134,9 @@ void createPet_whenUnexpectedError_shouldReturn500() throws Exception { when(petService.createPet(any(), any(), any())) .thenThrow(new RuntimeException("Unexpected failure")); - mockMvc.perform(post("/pets") + mockMvc.perform(post("/api/pets") .with(authenticatedAs(owner)) - .header("currentUserId", ownerId) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isInternalServerError()); @@ -145,37 +145,31 @@ void createPet_whenUnexpectedError_shouldReturn500() throws Exception { @Test void getPetById_shouldReturn200WithPetResponse() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(owner); when(petService.getPetById(any(), any())).thenReturn(pet); - mockMvc.perform(get("/pets/{petId}", petId) - .with(authenticatedAs(owner)) - .header("currentUserId", ownerId)) + mockMvc.perform(get("/api/pets/{petId}", petId) + .with(authenticatedAs(owner))) .andExpect(status().isOk()) .andExpect(jsonPath("$.name").value("Molly")); } @Test void getPetById_whenNotFound_shouldReturn404() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(owner); when(petService.getPetById(any(), any())) .thenThrow(new ResourceNotFoundException("Pet", petId)); - mockMvc.perform(get("/pets/{petId}", petId) - .with(authenticatedAs(owner)) - .header("currentUserId", ownerId)) + mockMvc.perform(get("/api/pets/{petId}", petId) + .with(authenticatedAs(owner))) .andExpect(status().isNotFound()); } @Test void getPetById_whenForbidden_shouldReturn403() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(vet); when(petService.getPetById(any(), any())) .thenThrow(new ForbiddenException("Du har inte behörighet att se detta djur")); - mockMvc.perform(get("/pets/{petId}", petId) - .with(authenticatedAs(vet)) - .header("currentUserId", UUID.randomUUID())) + mockMvc.perform(get("/api/pets/{petId}", petId) + .with(authenticatedAs(vet))) .andExpect(status().isForbidden()); } // GET /pets/owner/{ownerId} @@ -184,9 +178,8 @@ void getPetById_whenForbidden_shouldReturn403() throws Exception { void getPetsByOwner_shouldReturn200WithList() throws Exception { when(petService.getPetsByOwner(any(), any())).thenReturn(List.of(pet)); - mockMvc.perform(get("/pets/owner/{ownerId}", ownerId) - .with(authenticatedAs(owner)) - .header("currentUserId", ownerId)) + mockMvc.perform(get("/api/pets/owner/{ownerId}", ownerId) + .with(authenticatedAs(owner))) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].name").value("Molly")); } @@ -196,9 +189,8 @@ void getPetsByOwner_whenForbidden_shouldReturn403() throws Exception { when(petService.getPetsByOwner(any(), any())) .thenThrow(new ForbiddenException("Du saknar behörighet")); - mockMvc.perform(get("/pets/owner/{ownerId}", ownerId) - .with(authenticatedAs(vet)) - .header("currentUserId", UUID.randomUUID())) + mockMvc.perform(get("/api/pets/owner/{ownerId}", ownerId) + .with(authenticatedAs(vet))) .andExpect(status().isForbidden()); } @@ -209,9 +201,9 @@ void updatePet_shouldReturn200WithUpdatedPetResponse() throws Exception { Pet updated = new Pet(owner, "Harry", "Katt", "Siamese", LocalDate.of(2021, 3, 5), new BigDecimal("5.00")); when(petService.updatePet(any(), any(), any())).thenReturn(updated); - mockMvc.perform(put("/pets/{petId}", petId) + mockMvc.perform(put("/api/pets/{petId}", petId) .with(authenticatedAs(owner)) - .header("currentUserId", ownerId) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isOk()) @@ -223,9 +215,9 @@ void updatePet_whenNotFound_shouldReturn404() throws Exception { when(petService.updatePet(any(), any(), any())) .thenThrow(new ResourceNotFoundException("Pet", petId)); - mockMvc.perform(put("/pets/{petId}", petId) + mockMvc.perform(put("/api/pets/{petId}", petId) .with(authenticatedAs(owner)) - .header("currentUserId", ownerId) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isNotFound()); @@ -236,9 +228,9 @@ void updatePet_whenForbidden_shouldReturn403() throws Exception { when(petService.updatePet(any(), any(), any())) .thenThrow(new ForbiddenException("Du saknar behörighet")); - mockMvc.perform(put("/pets/{petId}", petId) + mockMvc.perform(put("/api/pets/{petId}", petId) .with(authenticatedAs(vet)) - .header("currentUserId", UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(validPetRequest()))) .andExpect(status().isForbidden()); @@ -249,36 +241,30 @@ void updatePet_whenForbidden_shouldReturn403() throws Exception { @Test void deletePet_shouldReturn204() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(owner); doNothing().when(petService).deletePet(any(), any()); - mockMvc.perform(delete("/pets/{petId}", petId) - .with(authenticatedAs(owner)) - .header("currentUserId", ownerId)) + mockMvc.perform(delete("/api/pets/{petId}", petId) + .with(authenticatedAs(owner))) .andExpect(status().isNoContent()); } @Test void deletePet_whenNotFound_shouldReturn404() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(owner); doThrow(new ResourceNotFoundException("Pet", petId)) .when(petService).deletePet(any(), any()); - mockMvc.perform(delete("/pets/{petId}", petId) - .with(authenticatedAs(owner)) - .header("currentUserId", ownerId)) + mockMvc.perform(delete("/api/pets/{petId}", petId) + .with(authenticatedAs(owner))) .andExpect(status().isNotFound()); } @Test void deletePet_whenForbidden_shouldReturn403() throws Exception { - when(userService.getUserEntityById(any())).thenReturn(vet); doThrow(new ForbiddenException("Du har inte behörighet att radera detta djur")) .when(petService).deletePet(any(), any()); - mockMvc.perform(delete("/pets/{petId}", petId) - .with(authenticatedAs(vet)) - .header("currentUserId", UUID.randomUUID())) + mockMvc.perform(delete("/api/pets/{petId}", petId) + .with(authenticatedAs(vet))) .andExpect(status().isForbidden()); } From aebc6cf4525b54308758084643c9ab812478bc9e Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Wed, 15 Apr 2026 12:38:27 +0200 Subject: [PATCH 3/3] docs: update API documentation to reflect new `/api/pets` base path adjustments --- API.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/API.md b/API.md index fd5ff055..87ecc3d7 100644 --- a/API.md +++ b/API.md @@ -119,13 +119,13 @@ const getKliniker = async () => { Visar alla djur som tillhör den inloggade djurägaren. -**`GET /pets/owner/{ownerId}`** +**`GET /api/pets/owner/{ownerId}`** ```javascript const getMinaDjur = async () => { const ownerId = 'c3d4e5f6-a7b8-4c5d-0e1f-a2b3c4d5e6f7'; // Annas ID - const response = await fetch(`http://localhost:8080/pets/owner/${ownerId}`, { + const response = await fetch(`http://localhost:8080/api/pets/owner/${ownerId}`, { headers: { 'X-Dev-User': 'anna@test.se' } @@ -170,11 +170,11 @@ const getMinaDjur = async () => { Registrera ett nytt djur för den inloggade ägaren. -**`POST /pets`** +**`POST /api/pets`** ```javascript const skapaDjur = async () => { - const response = await fetch('http://localhost:8080/pets', { + const response = await fetch('http://localhost:8080/api/pets', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -657,15 +657,15 @@ Kolumnen "Auth" visar vem som kan anropa endpointen. { "id": "uuid", "name": "...", "address": "...", "phoneNumber": "..." } ``` -### Djur (`/pets`) +### Djur (`/api/pets`) | Metod | URL | Auth | Beskrivning | Request body | |-------|-----|------|-------------|--------------| -| POST | `/pets` | OWNER/ADMIN (Policy) | Skapa djur. Admin kan ange `?ownerId=uuid` | `{ name, species, breed, dateOfBirth, weightKg }` | -| GET | `/pets/{petId}` | OWNER/VET/ADMIN (Policy) | Hamta ett djur | — | -| GET | `/pets/owner/{ownerId}` | OWNER/ADMIN (Policy) | Hamta alla djur for en ägare | — | -| PUT | `/pets/{petId}` | OWNER/ADMIN (Policy) | Uppdatera djurinfo | `{ name, species, breed, dateOfBirth, weightKg }` | -| DELETE | `/pets/{petId}` | OWNER/ADMIN (Policy) | Ta bort djur | — | +| POST | `/api/pets` | OWNER/ADMIN (Policy) | Skapa djur. Admin kan ange `?ownerId=uuid` | `{ name, species, breed, dateOfBirth, weightKg }` | +| GET | `/api/pets/{petId}` | OWNER/VET/ADMIN (Policy) | Hamta ett djur | — | +| GET | `/api/pets/owner/{ownerId}` | OWNER/ADMIN (Policy) | Hamta alla djur for en ägare | — | +| PUT | `/api/pets/{petId}` | OWNER/ADMIN (Policy) | Uppdatera djurinfo | `{ name, species, breed, dateOfBirth, weightKg }` | +| DELETE | `/api/pets/{petId}` | OWNER/ADMIN (Policy) | Ta bort djur | — | **Svar (PetResponse):** ```json