From cd4bebe5691556952e00bf860e1ff719e3f69767 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Sun, 8 Sep 2024 17:14:55 +0300 Subject: [PATCH 01/10] Dummy --- src/main/kotlin/rest_api/Owner.kt | 3 +++ src/main/kotlin/rest_api/Pet.kt | 5 ++++ src/main/kotlin/rest_api/ownerController.kt | 24 ++++++++++++++++++ src/main/kotlin/rest_api/petController.kt | 28 +++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/main/kotlin/rest_api/Owner.kt create mode 100644 src/main/kotlin/rest_api/Pet.kt create mode 100644 src/main/kotlin/rest_api/ownerController.kt create mode 100644 src/main/kotlin/rest_api/petController.kt diff --git a/src/main/kotlin/rest_api/Owner.kt b/src/main/kotlin/rest_api/Owner.kt new file mode 100644 index 000000000..18b7d52e6 --- /dev/null +++ b/src/main/kotlin/rest_api/Owner.kt @@ -0,0 +1,3 @@ +package rest_api + +data class Owner(val ownerId: Long, val name: String, val companyId: Long, val employeeId: Long) \ No newline at end of file diff --git a/src/main/kotlin/rest_api/Pet.kt b/src/main/kotlin/rest_api/Pet.kt new file mode 100644 index 000000000..00aaf20b8 --- /dev/null +++ b/src/main/kotlin/rest_api/Pet.kt @@ -0,0 +1,5 @@ +package rest_api + +import java.sql.Date + +data class Pet(val petId: Long, val name: String, val type: String, val companyId: Int, val dateOfArrival: Date) \ No newline at end of file diff --git a/src/main/kotlin/rest_api/ownerController.kt b/src/main/kotlin/rest_api/ownerController.kt new file mode 100644 index 000000000..1b7c09faa --- /dev/null +++ b/src/main/kotlin/rest_api/ownerController.kt @@ -0,0 +1,24 @@ +package rest_api + +import jakarta.ws.rs.* +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller + + +@Controller +@Path("/api/ron/owners/envelopes") +@Produces(MediaType.APPLICATION_JSON) +class ownerResource { + @GET + @Path("/{ownerId}") + fun getPetType(@PathParam("ownerId") ownerId: Long): Response { + if (ownerId.toInt() == 123){ + throw NotFoundException("Pet not found") + } + else { + Response.status(Response.Status.UNAUTHORIZED).build() + return Response.ok("some Owner").build() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/rest_api/petController.kt b/src/main/kotlin/rest_api/petController.kt new file mode 100644 index 000000000..4593a48c5 --- /dev/null +++ b/src/main/kotlin/rest_api/petController.kt @@ -0,0 +1,28 @@ +package rest_api + +import jakarta.ws.rs.GET +import jakarta.ws.rs.NotFoundException +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller + +@Controller +@Path("/api/ron/pets/envelopes") +@Produces(MediaType.APPLICATION_JSON) + +class petResource { + @GET + @Path("/{petId}/type") + fun getPetType(@PathParam("petId") petId: Long): Response { + if (petId.toInt() == 123){ + throw NotFoundException("Pet not found") + } + else { + Response.status(Response.Status.UNAUTHORIZED).build() + return Response.ok("parrot").build() + } + } +} \ No newline at end of file From 53ec4ca83ae6771c04c81f863cbbb22663a6ba27 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Sun, 8 Sep 2024 21:20:17 +0300 Subject: [PATCH 02/10] Implement REST API --- .../{ => com/hibob/academy}/rest_api/Owner.kt | 2 +- .../hibob/academy/rest_api/OwnerResource.kt | 77 +++++++++++++++ .../{ => com/hibob/academy}/rest_api/Pet.kt | 4 +- .../hibob/academy/rest_api/PetController.kt | 96 +++++++++++++++++++ src/main/kotlin/rest_api/ownerController.kt | 24 ----- src/main/kotlin/rest_api/petController.kt | 28 ------ 6 files changed, 176 insertions(+), 55 deletions(-) rename src/main/kotlin/{ => com/hibob/academy}/rest_api/Owner.kt (73%) create mode 100644 src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt rename src/main/kotlin/{ => com/hibob/academy}/rest_api/Pet.kt (66%) create mode 100644 src/main/kotlin/com/hibob/academy/rest_api/PetController.kt delete mode 100644 src/main/kotlin/rest_api/ownerController.kt delete mode 100644 src/main/kotlin/rest_api/petController.kt diff --git a/src/main/kotlin/rest_api/Owner.kt b/src/main/kotlin/com/hibob/academy/rest_api/Owner.kt similarity index 73% rename from src/main/kotlin/rest_api/Owner.kt rename to src/main/kotlin/com/hibob/academy/rest_api/Owner.kt index 18b7d52e6..a2a928b97 100644 --- a/src/main/kotlin/rest_api/Owner.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/Owner.kt @@ -1,3 +1,3 @@ -package rest_api +package com.hibob.academy.rest_api data class Owner(val ownerId: Long, val name: String, val companyId: Long, val employeeId: Long) \ No newline at end of file diff --git a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt new file mode 100644 index 000000000..a376fa911 --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt @@ -0,0 +1,77 @@ +package com.hibob.academy.rest_api + +import jakarta.ws.rs.* +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller + +val owners = mutableListOf( + Owner(1L,"Ron", 101L, 10L), + Owner(2L,"Or", 102L, 11L), + Owner(3L,"Noam", 103L, 12L) +) + + +@Controller +@Path("/api/ron/owners/envelopes") +@Produces(MediaType.APPLICATION_JSON) +class OwnerResource { + + //GET: Retrieve all owners + @GET + fun getAll() : Response { + return Response.ok(owners).build() + } + + //GET: Retrieve owner by ownerId + @GET + @Path("/{ownerId}") + fun getById(@PathParam("ownerId") ownerId: Long): Response { + val owner = owners.find { it.ownerId == ownerId } + return when{ + owner == null ->{ + throw NotFoundException("No owner with id $ownerId") + } + ownerId == 123L ->{ + Response.status(Response.Status.UNAUTHORIZED).build() + } + else ->{ + Response.ok(owner.toString()).build() + } + } + } + + @POST + fun addOwner(newOwner : Owner) : Response { + owners.add(newOwner) + return Response.status(Response.Status.CREATED).entity(newOwner).build() + } + + //PUT: Update a owner by ownerId + @PUT + @Path("/{ownerId}") + fun updateOwner(@PathParam("ownerId") ownerId: Long, updatedOwner: Owner): Response { + val index = owners.indexOfFirst { it.ownerId == ownerId } + return if (index>=0){ + owners[index] = updatedOwner.copy(ownerId = ownerId) + Response.ok(updatedOwner).build() + } + else{ + throw NotFoundException("No owner with id $ownerId") + } + } + + //DELETE: Delete an owner by ownerId + @DELETE + @Path("/{ownerId}") + fun deleteOwner(@PathParam("ownerId") ownerId: Long): Response { + val owner = owners.find { it.ownerId == ownerId } + return if(owner != null) { + owners.remove(owner) + Response.ok("${owner.toString()} Has been removed").build() + } + else + throw NotFoundException("No owner with id $ownerId") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/rest_api/Pet.kt b/src/main/kotlin/com/hibob/academy/rest_api/Pet.kt similarity index 66% rename from src/main/kotlin/rest_api/Pet.kt rename to src/main/kotlin/com/hibob/academy/rest_api/Pet.kt index 00aaf20b8..dc04031e4 100644 --- a/src/main/kotlin/rest_api/Pet.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/Pet.kt @@ -1,5 +1,5 @@ -package rest_api +package com.hibob.academy.rest_api -import java.sql.Date +import java.util.Date data class Pet(val petId: Long, val name: String, val type: String, val companyId: Int, val dateOfArrival: Date) \ No newline at end of file diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt new file mode 100644 index 000000000..3268ff50a --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -0,0 +1,96 @@ +package com.hibob.academy.rest_api + +import jakarta.ws.rs.* +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller +import java.util.Date + +val pets = mutableListOf( + Pet(1L, "Buddy", "Dog", 101, Date()), + Pet(2L, "Whiskers", "Cat", 102, Date()), + Pet(3L, "Polly", "Parrot", 103, Date()) +) + +@Controller +@Path("/api/ron/pets/envelopes") +@Produces(MediaType.APPLICATION_JSON) + +class PetResource { + // GET: Retrieve pet by ID + //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" + @GET + @Path("/{petId}") + fun getPetType(@PathParam("petId") petId: Long): Response { + val pet = pets.find { it.petId == petId } + return when { + pet == null -> { + throw NotFoundException("Pet not found") // Pet not found + } + petId == 123L -> { + Response.status(Response.Status.UNAUTHORIZED).build() // Unauthorized for petId 123 + } + else -> { + Response.ok("Pet Type: ${pet.type}, Name: ${pet.name}, Company ID: ${pet.companyId}, Date of Arrival: ${pet.dateOfArrival}").build() + } + } + } + + // GET: Retrieve all pets + //Example-> "http://localhost:8080/api/ron/pets/envelopes" + @GET + fun getAllPets(): Response { + return Response.ok(pets).build() + } + + // POST: Add a new pet + //Example-> "http://localhost:8080/api/ron/pets/envelopes" + // "Content-Type: application/json" \ + // '{ + // "name": "Max", + // "type": "Dog", + // "companyId": 104, + // "dateOfArrival": "2024-09-06T12:00:00Z" + // }' + @POST + fun addPet(newPet: Pet): Response { + pets.add(newPet) + return Response.status(Response.Status.CREATED).entity(newPet).build() + } + + + // PUT: Update a pet by ID + //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" \ + // "Content-Type: application/json" + // { + // "name": "Buddy Updated", + // "type": "Dog", + // "companyId": 101, + // "dateOfArrival": "2024-09-06T12:00:00Z" + // } + @PUT + @Path("/{petId}") + fun updatePet(@PathParam("petId") petId: Long, updatedPet: Pet): Response { + val index = pets.indexOfFirst { it.petId == petId } + return if (index >= 0) { + pets[index] = updatedPet.copy(petId = petId) // Keep the same pet ID + Response.ok(updatedPet).build() + } else { + throw NotFoundException("Pet not found") + } + } + + // DELETE: Delete a pet by ID + //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" + @DELETE + @Path("/{petId}") + fun deletePet(@PathParam("petId") petId: Long): Response { + val pet = pets.find { it.petId == petId } + return if (pet != null) { + pets.remove(pet) + Response.ok("Pet with ID $petId deleted").build() + } else { + throw NotFoundException("Pet not found") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/rest_api/ownerController.kt b/src/main/kotlin/rest_api/ownerController.kt deleted file mode 100644 index 1b7c09faa..000000000 --- a/src/main/kotlin/rest_api/ownerController.kt +++ /dev/null @@ -1,24 +0,0 @@ -package rest_api - -import jakarta.ws.rs.* -import jakarta.ws.rs.core.MediaType -import jakarta.ws.rs.core.Response -import org.springframework.stereotype.Controller - - -@Controller -@Path("/api/ron/owners/envelopes") -@Produces(MediaType.APPLICATION_JSON) -class ownerResource { - @GET - @Path("/{ownerId}") - fun getPetType(@PathParam("ownerId") ownerId: Long): Response { - if (ownerId.toInt() == 123){ - throw NotFoundException("Pet not found") - } - else { - Response.status(Response.Status.UNAUTHORIZED).build() - return Response.ok("some Owner").build() - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/rest_api/petController.kt b/src/main/kotlin/rest_api/petController.kt deleted file mode 100644 index 4593a48c5..000000000 --- a/src/main/kotlin/rest_api/petController.kt +++ /dev/null @@ -1,28 +0,0 @@ -package rest_api - -import jakarta.ws.rs.GET -import jakarta.ws.rs.NotFoundException -import jakarta.ws.rs.Path -import jakarta.ws.rs.PathParam -import jakarta.ws.rs.Produces -import jakarta.ws.rs.core.MediaType -import jakarta.ws.rs.core.Response -import org.springframework.stereotype.Controller - -@Controller -@Path("/api/ron/pets/envelopes") -@Produces(MediaType.APPLICATION_JSON) - -class petResource { - @GET - @Path("/{petId}/type") - fun getPetType(@PathParam("petId") petId: Long): Response { - if (petId.toInt() == 123){ - throw NotFoundException("Pet not found") - } - else { - Response.status(Response.Status.UNAUTHORIZED).build() - return Response.ok("parrot").build() - } - } -} \ No newline at end of file From 10f2cc12531540779f56c582df548cf4a3acf9db Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Mon, 9 Sep 2024 22:20:50 +0300 Subject: [PATCH 03/10] Gady's Review- If the url is /pets/{petId} then usually it means that you want all or some details of the pet. In your case if you are just returning the type I would change the url to reflect this. --- src/main/kotlin/com/hibob/academy/rest_api/PetController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt index 3268ff50a..31d8b6d52 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -20,7 +20,7 @@ class PetResource { // GET: Retrieve pet by ID //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" @GET - @Path("/{petId}") + @Path("/{petId}/type") fun getPetType(@PathParam("petId") petId: Long): Response { val pet = pets.find { it.petId == petId } return when { From 53ce9422c6f9f179615c635d18e9b1203ac40270 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Mon, 9 Sep 2024 22:23:49 +0300 Subject: [PATCH 04/10] Gady's Review-I think since the Pet is not a complex class and only consists of basic parameters types, you can probably use Response.ok().entity(pet).build() and it will serialize the object already to a readable string. --- src/main/kotlin/com/hibob/academy/rest_api/PetController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt index 31d8b6d52..34a18aecc 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -31,7 +31,7 @@ class PetResource { Response.status(Response.Status.UNAUTHORIZED).build() // Unauthorized for petId 123 } else -> { - Response.ok("Pet Type: ${pet.type}, Name: ${pet.name}, Company ID: ${pet.companyId}, Date of Arrival: ${pet.dateOfArrival}").build() + Response.ok().entity(pet).build() } } } From 91b4e81e8bb79af8a32cca0eb170b08c1c5f498b Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Mon, 9 Sep 2024 22:41:59 +0300 Subject: [PATCH 05/10] Gady's Review-The more kotlin way would be do do owner?.let { } ?: throw Exception --- .../com/hibob/academy/rest_api/OwnerResource.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt index a376fa911..b3282101f 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt @@ -66,12 +66,16 @@ class OwnerResource { @Path("/{ownerId}") fun deleteOwner(@PathParam("ownerId") ownerId: Long): Response { val owner = owners.find { it.ownerId == ownerId } - return if(owner != null) { + return owner?.let { owners.remove(owner) Response.ok("${owner.toString()} Has been removed").build() - } - else - throw NotFoundException("No owner with id $ownerId") + }?: throw NotFoundException("No owner with id $ownerId") +// return if(owner != null) { +// owners.remove(owner) +// Response.ok("${owner.toString()} Has been removed").build() +// } +// else +// throw NotFoundException("No owner with id $ownerId") } } \ No newline at end of file From 66f27ef032f94697fbe6dcb6b7ea4a96921179ff Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Tue, 10 Sep 2024 17:52:28 +0300 Subject: [PATCH 06/10] Gady review - /envelopes shouldn't be part of the path. --- src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt index b3282101f..204541495 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt @@ -13,7 +13,7 @@ val owners = mutableListOf( @Controller -@Path("/api/ron/owners/envelopes") +@Path("/api/ron/owners") @Produces(MediaType.APPLICATION_JSON) class OwnerResource { From ddc9df7d2480eb07c3b37f7b097e10335545a1c4 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Tue, 10 Sep 2024 17:53:45 +0300 Subject: [PATCH 07/10] Fixed! --- src/main/kotlin/com/hibob/academy/rest_api/PetController.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt index 34a18aecc..c0eb459ea 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -58,7 +58,6 @@ class PetResource { return Response.status(Response.Status.CREATED).entity(newPet).build() } - // PUT: Update a pet by ID //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" \ // "Content-Type: application/json" From a2630eaed86ac80c47f0923427eb0bef36f7da26 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Thu, 12 Sep 2024 09:49:32 +0300 Subject: [PATCH 08/10] delete comment --- src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt index 204541495..4d08a0e95 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt @@ -70,12 +70,6 @@ class OwnerResource { owners.remove(owner) Response.ok("${owner.toString()} Has been removed").build() }?: throw NotFoundException("No owner with id $ownerId") -// return if(owner != null) { -// owners.remove(owner) -// Response.ok("${owner.toString()} Has been removed").build() -// } -// else -// throw NotFoundException("No owner with id $ownerId") } } \ No newline at end of file From 2274ccbe421ae334cacd2cbcd2db36e3259bc7d4 Mon Sep 17 00:00:00 2001 From: Ron Azar Date: Mon, 16 Sep 2024 07:53:04 +0300 Subject: [PATCH 09/10] No need envelopes here either. --- src/main/kotlin/com/hibob/academy/rest_api/PetController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt index c0eb459ea..e1342464f 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -13,7 +13,7 @@ val pets = mutableListOf( ) @Controller -@Path("/api/ron/pets/envelopes") +@Path("/api/ron/pets") @Produces(MediaType.APPLICATION_JSON) class PetResource { From 97f2e24e900e5f521b2fea13fc0fa07d0141d77b Mon Sep 17 00:00:00 2001 From: Ron Azar <131266999+RonAzar@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:01:41 +0300 Subject: [PATCH 10/10] Sending all REST API calls In custom serialization (#15) --- src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt | 4 +++- src/main/kotlin/com/hibob/academy/rest_api/PetController.kt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt index 4d08a0e95..62b9ccb44 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/OwnerResource.kt @@ -36,7 +36,8 @@ class OwnerResource { Response.status(Response.Status.UNAUTHORIZED).build() } else ->{ - Response.ok(owner.toString()).build() + //Sending JSON + Response.ok(owner).build() } } } @@ -54,6 +55,7 @@ class OwnerResource { val index = owners.indexOfFirst { it.ownerId == ownerId } return if (index>=0){ owners[index] = updatedOwner.copy(ownerId = ownerId) + //Sending JSON Response.ok(updatedOwner).build() } else{ diff --git a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt index e1342464f..601d04842 100644 --- a/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt +++ b/src/main/kotlin/com/hibob/academy/rest_api/PetController.kt @@ -58,6 +58,7 @@ class PetResource { return Response.status(Response.Status.CREATED).entity(newPet).build() } + // PUT: Update a pet by ID //Example-> "http://localhost:8080/api/ron/pets/envelopes/1" \ // "Content-Type: application/json"