An open API service indexing awesome lists of open source software.

https://github.com/kundanchourasiya/crud-operations-with-custom-api-response

In this Api we customize Api Response.
https://github.com/kundanchourasiya/crud-operations-with-custom-api-response

java java8-stream lombok mysql postman spring-jpa springboot swagger-ui validation

Last synced: about 2 months ago
JSON representation

In this Api we customize Api Response.

Awesome Lists containing this project

README

        

# Crud-Operations-With-Custom-Api-Response

> [!NOTE]
> ### In this Api we customize Api Response.

## Tech Stack
- Java
- Spring Framework
- Spring Boot
- Spring Data JPA
- lombok
- Validation
- MySQL
- Postman
- Swagger UI

## Modules
* Student Modules

## Documentation
Swagger UI Documentation - http://localhost:8080/swagger-ui/

## Installation & Run
Before running the API server, you should update the database config inside the application.properties file.
Update the port number, username and password as per your local database config.

```
spring.datasource.url=jdbc:mysql://localhost:3306/mydb;
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
```

## API Root Endpoint

```
https://localhost:8080/
http://localhost:8080/swagger-ui/
user this data for checking purpose.
```
## Step To Be Followed
> 1. Create Rest Api will return to Student Details.
>
> **Project Documentation**
> - **Entity** - Student (class)
> - **Payload** - StudentDto, ApiResponceDto (class)
> - **Repository** - StudentRepository (interface)
> - **Service** - StudentService (interface), StudentServiceImpl (class)
> - **Controller** - StudentController (Class)
> - **Global Exception** - GlobalException, UserNotFoundException (class)
>
> 2. Run the application and get All API Response similar types.

## Important Dependency to be used
1. For rest api
```

org.springframework.boot
spring-boot-starter-web

```

2. For Getter and Setter
```

org.projectlombok
lombok
true

```

3. For Validation
```

org.springframework.boot
spring-boot-starter-validation

```

4. For Swagger
```

org.springdoc
springdoc-openapi-starter-webmvc-ui
2.3.0

```

5. For Mysql and JPA
```

com.mysql
mysql-connector-j
runtime

org.springframework.boot
spring-boot-starter-data-jpa

```

## Create Student class in Entity Package.
```
package com.it.Entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import java.time.LocalDateTime;

@Getter
@Setter
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

@Column(name = "FullName", nullable = false)
private String fullName;

@Column(name = "Email", nullable = false, unique = true)
private String email;

@Column(name = "Password")
private String password;

@Column(name = "Mobile", nullable = false, unique = true)
private String mobile;

@Column(name = "Age", nullable = false)
private Long age;

@Column(name = "Gender", nullable = false)
private String gender;

@CreationTimestamp
@Column(name = "CreateDate", updatable = false)
private LocalDateTime createDate;

@UpdateTimestamp
@Column(name = "UpdateDate", insertable = false)
private LocalDateTime updateDate;

}
```

## Create StudentRepository interface in repository package.

```package com.it.Repository;

import com.it.Entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StudentRepository extends JpaRepository {

boolean existsByEmail(String email);
boolean existsByMobile(String mobile);

List findByFullNameContainingIgnoreCase(String fullname);

}
```

## Create StudentService interface and StudentServiceImpl class in Service package.

### *StudentService*
```
public interface StudentService {

// create Student
public StudentDto createStudent(StudentDto dto);

// get All student Details
public List getAllStudent();

// get All student in page Format
public Page getAllStudentPage(Pageable pageable);

// get single Student details
public StudentDto getStudent(Long id);

// Update Student Details
public StudentDto updateStudent(Long id, StudentDto dto);

// Delete Student Details
public StudentDto deleteStudent(Long id);

// Search Student details using name
public List searchByName(String name);

}
```

### *StudentService*
```
@Service
public class StudentServiceImpl implements StudentService {
private StudentRepository studentRepository;

public StudentServiceImpl(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}

// map to dto
private StudentDto mapTODto(Student student) {
StudentDto dto = new StudentDto();
dto.setId(student.getId());
dto.setFullName(student.getFullName());
dto.setEmail(student.getEmail());
dto.setPassword(student.getPassword());
dto.setMobile(student.getMobile());
dto.setGender(student.getGender());
dto.setAge(student.getAge());
return dto;
}

// map to Entity
private Student mapToEntity(StudentDto dto) {
Student student = new Student();
student.setId(dto.getId());
student.setFullName(dto.getFullName());
student.setEmail(dto.getEmail());
student.setPassword(dto.getPassword());
student.setMobile(dto.getMobile());
student.setGender(dto.getGender());
student.setAge(dto.getAge());
return student;
}

@Override
public StudentDto createStudent(StudentDto dto) {
Student student = new Student();
student.setId(dto.getId());
student.setFullName(dto.getFullName());
student.setEmail(dto.getEmail());
student.setPassword(dto.getPassword());
student.setGender(dto.getGender());
student.setAge(dto.getAge());
student.setMobile(dto.getMobile());

if (studentRepository.existsByEmail(dto.getEmail())) {
throw new IllegalArgumentException("User email already exist.");
}
if (studentRepository.existsByMobile(dto.getMobile())) {
throw new IllegalArgumentException("User Mobile no. already exist.");
}

Student saveStudent = studentRepository.save(student);
StudentDto studentDto = mapTODto(saveStudent);
return studentDto;
}

@Override
public List getAllStudent() {
List studentList = studentRepository.findAll();
List studentDtoList = studentList.stream().map(this::mapTODto).collect(Collectors.toUnmodifiableList());
return studentDtoList;
}

@Override
public Page getAllStudentPage(Pageable pageable) {
Page studentPage = studentRepository.findAll(pageable);
List studentDtoList = studentPage.getContent().stream().map(this::mapTODto).collect(Collectors.toList());
return new PageImpl<>(studentDtoList, pageable, studentPage.getTotalPages());
}

@Override
public StudentDto getStudent(Long id) {
Student student = studentRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Student Not Found By Id"));
StudentDto studentDto = mapTODto(student);
return studentDto;
}

@Override
public StudentDto updateStudent(Long id, StudentDto dto) {
Student student = studentRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Student Not Found By Id"));
student.setId(id);
student.setFullName(dto.getFullName());
student.setEmail(dto.getEmail());
student.setPassword(dto.getPassword());
student.setGender(dto.getGender());
student.setAge(dto.getAge());
student.setMobile(dto.getMobile());
Student save = studentRepository.save(student);
StudentDto studentDto = mapTODto(save);
return studentDto;
}

@Override
public StudentDto deleteStudent(Long id) {
Student student = studentRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Student Not Found By Id"));
studentRepository.deleteById(student.getId());
StudentDto studentDto = mapTODto(student);
return studentDto;
}

@Override
public List searchByName(String name) {
List studentList = studentRepository.findByFullNameContainingIgnoreCase(name);
List studentDtoList = studentList.stream().map(this::mapTODto).collect(Collectors.toUnmodifiableList());
return studentDtoList;
}
}
```

## Create ApiResponse and StudentDto class inside the Payload Package.

### *StudentDto*
```
@Data
public class StudentDto {

private Long id;

@NotBlank(message = "This Filed is required")
private String fullName;

@NotBlank(message = "This Filed is required")
@Email(message = "Enter the Valid mail id")
private String email;

@NotBlank(message = "This Filed is required")
@Pattern(regexp = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$", message = "Password must have of minimum 8 Characters and at least one uppercase letter, one lowercase letter, one number and one special character")
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

@NotNull(message = "This Filed is required")
@Size(min = 10, max = 10, message = "size must be 10 digits.")
@Pattern(regexp = "^\\d{10}$", message = "Phone number must be exactly 10 digits Only.")
private String mobile;

@NotNull(message = "This Filed is required")
@Min(18)
@Max(60)
private Long age;

@NotBlank(message = "This Filed is required")
private String gender;
}

```
### *ApiResponseDto*
```
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse {

private boolean success;
private String massage;
private T Data;

}
```

### *Create GlobalException class and UserNotFoundException class inside the GlobalException Package.*

### *GlobalException*

```
@RestControllerAdvice
public class GlobalExceptionHandler {

// General error handler
@ExceptionHandler(Exception.class)
public ResponseEntity> handleGeneral(Exception ex) {
ApiResponse response = new ApiResponse<>(false, ex.getMessage(), null);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}

// UserNotFoundException handler
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity> handleUserNotFound(UserNotFoundException ex) {
ApiResponse response = new ApiResponse<>(false, ex.getMessage(), null);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}

// IllegalArgumentException Handler
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity> IllegalArgumentExceptionHandle(IllegalArgumentException ex) {
ApiResponse response = new ApiResponse<>(false, ex.getMessage(), null);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}

// MethodArgumentNotValidException handler
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity> handlerInvalidArgument(MethodArgumentNotValidException ex) {

Map errorMsg = new HashMap<>();
ex.getBindingResult().getFieldErrors()
.forEach(error -> errorMsg.put(error.getField(), error.getDefaultMessage()));
ApiResponse response = new ApiResponse<>(false, "Something went wrong", errorMsg);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
}
```

### *UserNotFoundException*
```
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message) {
super(message);
}
}
```

### *Create StudentController class inside the Controller Package.*

```
@RestController
@RequestMapping("/student")
public class StudentController {

private StudentService studentService;

public StudentController(StudentService studentService) {
this.studentService = studentService;
}

//URL : http://localhost:8080/student/create
@PostMapping("/create")
public ResponseEntity> createUser(@Valid @RequestBody StudentDto dto) {
StudentDto student = studentService.createStudent(dto);
ApiResponse> apiResponse = new ApiResponse<>(true, "Student saved!!!", student);
return ResponseEntity.status(200).body(apiResponse);
}

//URL : http://localhost:8080/student/all-student
@GetMapping("/all-student")
public ResponseEntity> getAllStudent() {
List allStudent = studentService.getAllStudent();
ApiResponse> allStudentDetails = new ApiResponse<>(true, "All student details", allStudent);
return ResponseEntity.status(200).body(allStudentDetails);
}

//URL : http://localhost:8080/student/allstudent
//URL : http://localhost:8080/student/allstudent?page=0
//URL : http://localhost:8080/student/allstudent?page=0&size=2
@GetMapping("/allstudent")
public ResponseEntity> getAllStudentPage(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "2") int size) {
Page allStudentPage = studentService.getAllStudentPage(PageRequest.of(page, size));
if (!allStudentPage.isEmpty()){
ApiResponse> allStudentDetailsInPage = new ApiResponse<>(true, "All student details in page", allStudentPage);
return ResponseEntity.status(200).body(allStudentDetailsInPage);
}
ApiResponse noStudentDetailsInPage = new ApiResponse<>(false, "No student Found ", null);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.NOT_FOUND.value())).body(noStudentDetailsInPage);
}

//URL : http://localhost:8080/student/get/3
@GetMapping("/get/{id}")
public ResponseEntity> getStudent(@PathVariable Long id) {
StudentDto student = studentService.getStudent(id);
ApiResponse studentDtoApiResponse = new ApiResponse<>(true, "Student record by Id", student);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.ACCEPTED.value())).body(studentDtoApiResponse);
}

//URL : http://localhost:8080/student/update/1
@PutMapping("/update/{id}")
public ResponseEntity> updateStudent(@PathVariable Long id, @Valid @RequestBody StudentDto dto) {
StudentDto studentDto = studentService.updateStudent(id, dto);
ApiResponse studentDtoApiResponse = new ApiResponse<>(true, "Student record update Successfully", studentDto);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.OK.value())).body(studentDtoApiResponse);
}

//URL : http://localhost:8080/student/delete/6
@DeleteMapping("/delete/{id}")
public ResponseEntity> deleteStudent(@PathVariable Long id) {
StudentDto student = studentService.deleteStudent(id);
ApiResponse studentDtoApiResponse = new ApiResponse<>(true, "Student id " + student.getId() + " Delete Successfully", null);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.OK.value())).body(studentDtoApiResponse);
}

//URL : http://localhost:8080/student/search?name=k
//URL : http://localhost:8080/student/search?name=sdghs
@GetMapping("/search")
public ResponseEntity> searchByName(@RequestParam(required = false) String name) {

List studentDtos = studentService.searchByName(name);
if (!studentDtos.isEmpty()) {
ApiResponse> studentFoundByName = new ApiResponse<>(true, "Student Found by name", studentDtos);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.FOUND.value())).body(studentFoundByName);
}
ApiResponse noStudentFoundByName = new ApiResponse<>(false, "No student Found by name", null);
return ResponseEntity.status(HttpStatusCode.valueOf(HttpStatus.NOT_FOUND.value())).body(noStudentFoundByName);
}
}

```

## Configure **_Swagger Definition_** to use Api Documentation and all Controller Documentation.

### *Swegger Defination*
```
// configure swagger OpenAPIDefinition
@OpenAPIDefinition(
info = @Info(
title = "Crud Operations with custom Api Response",
version = "1.0",
description = "In this Api we customize Api Response.",
contact = @Contact(
name = "Kundan Kumar Chourasiya",
email = "[email protected]"
)
),
servers = @Server(
url = "http://localhost:8080",
description = "Crud Operations with custom Api Response url"
)
)
```

### Following pictures will help to understand flow of API

### *Swagger*

![image](https://github.com/user-attachments/assets/ab1b5567-08de-4994-b51a-704b97401a3f)

### *PostMan Test Cases*

Url - http://localhost:8080/student/create
![image](https://github.com/user-attachments/assets/23227c38-af02-4a09-ae6f-b5f7a58a9720)

Url - http://localhost:8080/student/search?name=g

Url - http://localhost:8080/student/search?name=Armando
![image](https://github.com/user-attachments/assets/bae60f1d-eb55-45f1-849c-db2e78fee760)

Url - http://localhost:8080/student/all-student
![image](https://github.com/user-attachments/assets/f65d7d34-8d3c-48a4-9699-524741de0bee)

Url - http://localhost:8080/student/get/4
![image](https://github.com/user-attachments/assets/b6f69bc6-8a69-470c-9298-34cf62bb68d5)

Url - http://localhost:8080/student/update/6
![image](https://github.com/user-attachments/assets/f094ac96-78bb-495a-a857-32906a3be89c)

Url - http://localhost:8080/student/delete/6
![image](https://github.com/user-attachments/assets/aa86df71-5145-45fd-8ad6-11eb81a176db)

URL : http://localhost:8080/student/allstudent

URL : http://localhost:8080/student/allstudent?page=0

URL : http://localhost:8080/student/allstudent?page=0&size=2
![image](https://github.com/user-attachments/assets/965fa88d-de0d-4c9f-a323-2b73d9190cc4)