diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java
new file mode 100644
index 000000000..3a8dc4fa9
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java
@@ -0,0 +1,101 @@
+package org.springframework.samples.petclinic.owner;
+
+import jakarta.annotation.Nonnull;
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+@Entity
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+
+/**
+ * Simple business object representing a pet.
+ *
+ * @author Shreyas Prayag
+ */
+
+public class NewPet {
+
+ /**
+ * The unique identifier for the pet. This field is mapped to the "id" column in the
+ * "new_pet" table. It is automatically generated by the database when a new pet is
+ * created.
+ */
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ /**
+ * The name of the pet. This field is mapped to the "name" column in the "new_pet"
+ * table. It cannot be null and should not be empty.
+ */
+ @NotNull
+ private String name;
+
+ /**
+ * The date of birth of the pet. This field is mapped to the "birth_date" column in
+ * the "new_pet" table. It cannot be null and should not be empty.
+ */
+ private Date birthDate;
+
+ /**
+ * The owner of the pet.
+ *
+ * This field represents a many-to-one relationship between pets and their owners —
+ * each pet is associated with one owner, but an owner can have multiple pets.
+ *
+ *
+ * The relationship is mapped via the {@code owner_id} foreign key in the
+ * {@code new_pet} table.
+ *
+ *
+ * @see Owner
+ */
+ @ManyToOne
+ @JoinColumn(name = "owner_id")
+ private Owner owner;
+
+ /**
+ * The temperament of the pet.
+ *
+ * This field represents a many-to-one relationship between pets and their
+ * temperaments — each pet has one temperament, there can be more than one pets with
+ * one temperament.
+ *
+ *
+ * The relationship is mapped via the {@code temperament_id} foreign key in the
+ * {@code new_pet} table.
+ *
+ *
+ * @see PetTemperament
+ */
+ @ManyToOne()
+ @JoinColumn(name = "temperament_id")
+ private PetTemperament temperament;
+
+ /**
+ * The type of the pet.
+ *
+ * This field represents a many-to-one relationship between pets and their owners —
+ * each pet is associated with one type, but there can be multiple pets of a type.
+ *
+ *
+ * The relationship is mapped via the {@code type_id} foreign key in the
+ * {@code new_pet} table.
+ *
+ *
+ * @see Owner
+ */
+ @ManyToOne
+ @JoinColumn(name = "type_id")
+ private PetType type;
+
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java
new file mode 100644
index 000000000..11a2e9544
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java
@@ -0,0 +1,92 @@
+package org.springframework.samples.petclinic.owner;
+
+import org.springframework.hateoas.EntityModel;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
+
+/**
+ * new Controller to handle requests relating pet
+ *
+ * The existing controller is not a REST API controller. So this controller is created to
+ * cater Rest endpoints relating Pet.
+ *
+ * @author Shreyas Prayag
+ * @since 1.0
+ */
+@RestController
+@RequestMapping("owners/{ownerId}")
+public class NewPetController {
+
+ private final NewPetRepository petRepository;
+
+ NewPetController(NewPetRepository petRepository) {
+ this.petRepository = petRepository;
+ }
+
+ /**
+ * Retrieves a pet by its ID.
+ *
+ * This endpoint returns a pet based on the provided pet ID. If the pet with the given
+ * ID exists, it returns the pet details in the response body with a 200 OK status. If
+ * the pet is not found, a 404 Not Found status is returned.
+ *
+ * @param petId The ID of the pet to retrieve. It is expected to be a positive
+ * integer.
+ * @return A {@link ResponseEntity} containing the {@link Pet} object if found, or a
+ * 404 response if not found.
+ *
+ * this endpoint is hateoas compliant
+ */
+ @GetMapping("/pet/{petId}")
+ public ResponseEntity> getPetById(@PathVariable int ownerId, @PathVariable int petId) {
+
+ NewPet pet = petRepository.findById(petId);
+
+ if (pet == null) {
+ return ResponseEntity.notFound().build();
+ }
+
+ EntityModel petResource = EntityModel.of(pet);
+
+ // Add self link
+ petResource.add(linkTo(methodOn(NewPetController.class).getPetById(ownerId, petId)).withSelfRel());
+
+ // Add link to create new pet
+ petResource.add(linkTo(methodOn(NewPetController.class).createNewPet(ownerId, null)).withRel("create-new-pet"));
+
+ return ResponseEntity.ok(petResource);
+
+ }
+
+ /**
+ * Creates a new pet.
+ *
+ * This endpoint accepts a {@link Pet} object in the request body and saves it to the
+ * database. It returns the created {@link Pet} object along with a 201 Created HTTP
+ * status code. If the pet data is invalid, a 400 Bad Request status is returned.
+ *
+ * @param newPet The pet object to create. This is expected to contain the pet details
+ * in the request body.
+ * @return A {@link ResponseEntity} containing the created {@link Pet} object and a
+ * 201 Created status.
+ *
+ * this endpoint is hateoas compliant
+ */
+ @PostMapping("/pet")
+ public ResponseEntity> createNewPet(@PathVariable int ownerId, @RequestBody NewPet newPet) {
+
+ NewPet savedPet = petRepository.save(newPet);
+ EntityModel petResource = EntityModel.of(savedPet);
+
+ // Add self link
+ petResource.add(linkTo(methodOn(NewPetController.class).getPetById(ownerId, savedPet.getId())).withSelfRel());
+
+ return ResponseEntity.status(HttpStatus.CREATED).body(petResource);
+
+ }
+
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java
new file mode 100644
index 000000000..0e0b0db35
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java
@@ -0,0 +1,33 @@
+package org.springframework.samples.petclinic.owner;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * Repository interface for managing {@link NewPet} entities.
+ *
+ * Extends {@link JpaRepository} to provide CRUD operations, pagination, and JPA-specific
+ * functionality.
+ *
+ *
+ * @author You
+ * @since 1.0
+ */
+public interface NewPetRepository extends JpaRepository {
+
+ /**
+ * Finds the pet with the given id.
+ * @param id The id of the pet to search for.
+ * @return a pet with the specified id.
+ *
+ */
+ NewPet findById(int id);
+
+ /**
+ * Saves the given pet
+ * @param newPet The pet object to be saved.
+ * @return pet object being saved.
+ *
+ */
+ NewPet save(NewPet newPet);
+
+}
diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java b/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java
new file mode 100644
index 000000000..ece2657bd
--- /dev/null
+++ b/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java
@@ -0,0 +1,46 @@
+package org.springframework.samples.petclinic.owner;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Entity
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+
+/**
+ * Simple business object representing pet temperament.
+ *
+ * @author Shreyas Prayag
+ */
+public class PetTemperament {
+
+ /**
+ * The unique identifier for the temperament. This field is mapped to the "id" column
+ * in the "pet_temperament" table. It is automatically generated by the database when
+ * a new temperament is created.
+ */
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ /**
+ * The Temperament of pet. This field is mapped to the "temperament" column in the
+ * "pet_temperament" table. It cannot be null and should not be empty.
+ */
+ @NotNull
+ private String temperament;
+
+ public PetTemperament(String temperament) {
+ this.temperament = temperament;
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 6ed985654..5a64972cf 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,13 +1,23 @@
# database init, supports mysql too
-database=h2
+database=mysql
spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql
spring.sql.init.data-locations=classpath*:db/${database}/data.sql
+
+# Data Source properties
+spring.datasource.url=jdbc:mysql://localhost:3306/petclinic
+spring.datasource.username=petclinic
+spring.datasource.password=petclinic
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+# Logging level for Hibernate SQL
+logging.level.org.hibernate.SQL=DEBUG
# Web
spring.thymeleaf.mode=HTML
# JPA
-spring.jpa.hibernate.ddl-auto=none
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.open-in-view=false
# Internationalization
diff --git a/src/test/java/org/springframework/samples/petclinic/owner/NewPetControllerTest.java b/src/test/java/org/springframework/samples/petclinic/owner/NewPetControllerTest.java
new file mode 100644
index 000000000..dded17291
--- /dev/null
+++ b/src/test/java/org/springframework/samples/petclinic/owner/NewPetControllerTest.java
@@ -0,0 +1,99 @@
+package org.springframework.samples.petclinic.owner;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.hamcrest.Matchers.is;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+@WebMvcTest(NewPetController.class)
+class NewPetControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private NewPetRepository petRepository;
+
+ private NewPet testPet;
+
+ private PetType testPetType;
+
+ @BeforeEach
+ void setup() {
+
+ testPetType = new PetType();
+ testPetType.setId(1);
+ testPetType.setName("Test");
+
+ testPet = new NewPet();
+ testPet.setId(1);
+ testPet.setName("Buddy");
+ testPet.setType(testPetType);
+ }
+
+ @Test
+ void getPetById_found() throws Exception {
+ when(petRepository.findById(1)).thenReturn(testPet);
+
+ mockMvc.perform(get("/owners/1/pet/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id", is(1)))
+ .andExpect(jsonPath("$.name", is("Buddy")))
+ .andExpect(jsonPath("$.type.name", is("Test")))
+ .andExpect(jsonPath("$._links.self.href").exists())
+ .andExpect(jsonPath("$._links.create-new-pet.href").exists());
+ }
+
+ @Test
+ void getPetById_notFound() throws Exception {
+ when(petRepository.findById(99)).thenReturn(null);
+
+ mockMvc.perform(get("/owners/1/pet/99")).andExpect(status().isNotFound());
+ }
+
+ @Test
+ void createNewPet_success() throws Exception {
+
+ testPetType = new PetType();
+ testPetType.setId(1);
+ testPetType.setName("Test1");
+
+ NewPet newPet = new NewPet();
+ newPet.setId(2);
+ newPet.setName("Whiskers");
+ newPet.setType(testPetType);
+
+ when(petRepository.save(any(NewPet.class))).thenReturn(newPet);
+
+ mockMvc.perform(post("/owners/1/pet").contentType(MediaType.APPLICATION_JSON).content(asJsonString(newPet)))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.id", is(2)))
+ .andExpect(jsonPath("$.name", is("Whiskers")))
+ .andExpect(jsonPath("$.type.name", is("Test1")))
+ .andExpect(jsonPath("$._links.self.href").exists());
+ }
+
+ // Utility method to convert objects to JSON string
+ private static String asJsonString(Object obj) {
+ try {
+ return new ObjectMapper().writeValueAsString(obj);
+ }
+ catch (Exception e) {
+ throw new RuntimeException("Failed to convert object to JSON string", e);
+ }
+ }
+
+}