Building an Airline Price Monitoring System: A Step-by-Step Guide [Part 1] Building an Airline Price Monitoring System: A Step-by-Step Guide [Part 2]
Content
- We write the level of Controllers. SubscriptionController
- Application testing
- Development plans
- conclusions
- useful links
We write the level of Controllers. SubscriptionController
The last step is to write a REST API through which we will communicate with the application. Spring boot starter web will be used for this . The SubscriptionController will have 4 methods for CRUD operations. For controllers, there is a set of annotations that make this work:- @Controller - used to add to the ApplicationContext;
- @RequestMapping("path") - determines that this class will have REST methods, also path - the path on which the request will begin;
- @PostMapping - for POST requests, used to create;
- @GetMapping - for GET requests, used for reading;
- @PutMapping - for PUT requests, used for editing;
- @DeleteMapping - for DELETE requests, used for deletion;
- @PathVariable means the variable will be set in the request URI;
- @RequestBody - means that the data will be in the request body;
- @Valid - means that the data will be validated, if they do not match, then there will be an error.
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionCreateDto;
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionDto;
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionUpdateDto;
import com.github.romankh3.flightsmonitoring.service.SubscriptionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* {@link Controller} to handle Subscriptions.
*/
@Api(value = "Operations with Subscriptions", tags = "Subscription Controller")
@RequestMapping(SubscriptionController.SUBSCRIPTION_CONTROLLER_EP)
@Controller
public class SubscriptionController {
public static final String SUBSCRIPTION_CONTROLLER_EP = "/subscription";
@Autowired
private SubscriptionService subscriptionService;
@ApiOperation("Create new subscription based on SubscriptionDto")
@PostMapping
public @ResponseBody
SubscriptionDto create(@RequestBody @Valid SubscriptionCreateDto dto) {
return subscriptionService.create(dto);
}
@ApiOperation("Finds all subscriptions based on email")
@GetMapping("/{email}")
public @ResponseBody
List<SubscriptionDto> findByEmail(@PathVariable final String email) {
return subscriptionService.findByEmail(email);
}
@ApiOperation("Updates subscription based on it ID")
@PutMapping("/{id}")
public SubscriptionDto update(@PathVariable final Long id,
@RequestBody @Valid SubscriptionUpdateDto dto) {
return subscriptionService.update(id, dto);
}
@ApiOperation("Deletes subscription based on it ID")
@DeleteMapping("/{id}")
public void delete(@PathVariable final Long id) {
subscriptionService.delete(id);
}
}
Let's also determine what new DTO classes have been added:
-
SubscriptionCreateDto
import com.fasterxml.jackson.annotation.JsonFormat; import com.github.romankh3.flightsmonitoring.repository.entity.Subscription; import io.swagger.annotations.ApiModelProperty; import java.time.LocalDate; import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import lombok.Data; /** * Data transfer object to create a {@link Subscription} object. */ @Data public class SubscriptionCreateDto { @NotNull @Email @ApiModelProperty(value = "Subscriber's email", example = "test@test.com") private String email; @NotNull @ApiModelProperty(value = "Country Code", example = "UA") private String country; @NotNull @ApiModelProperty(value = "Currency Code", example = "UAH") private String currency; @NotNull @ApiModelProperty(value = "Locale", example = "ru-RU") private String locale; @NotNull @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky") private String originPlace; @NotNull @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky") private String destinationPlace; @NotNull @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date front", example = "2019-12-18") private LocalDate outboundPartialDate; @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date back", example = "2019-12-25") private LocalDate inboundPartialDate; }
-
SubscriptionUpdateDto
import com.fasterxml.jackson.annotation.JsonFormat; import com.github.romankh3.flightsmonitoring.repository.entity.Subscription; import io.swagger.annotations.ApiModelProperty; import java.time.LocalDate; import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import lombok.Data; /** * Dto for updating {@link Subscription} object. */ @Data public class SubscriptionUpdateDto { @NotNull @Email @ApiModelProperty(value = "Subscriber's email", example = "test@test.com") private String email; @NotNull @ApiModelProperty(value = "Country Code", example = "UA") private String country; @NotNull @ApiModelProperty(value = "Currency Code", example = "UAH") private String currency; @NotNull @ApiModelProperty(value = "Locale", example = "ru-RU") private String locale; @NotNull @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky") private String originPlace; @NotNull @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky") private String destinationPlace; @NotNull @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date front", example = "2019-12-18") private LocalDate outboundPartialDate; @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date back", example = "2019-12-25") private LocalDate inboundPartialDate; }
-
SubscriptionDto
import com.fasterxml.jackson.annotation.JsonFormat; import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto; import io.swagger.annotations.ApiModelProperty; import java.time.LocalDate; import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import lombok.Data; /** * Data transfer object to see all the data related to subscription. */ @Data public class SubscriptionDto { private Long id; @NotNull @Email @ApiModelProperty(value = "Subscriber's email", example = "test@test.com") private String email; @NotNull @ApiModelProperty(value = "Country Code", example = "UA") private String country; @NotNull @ApiModelProperty(value = "Currency Code", example = "UAH") private String currency; @NotNull @ApiModelProperty(value = "Locale", example = "ru-RU") private String locale; @NotNull @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky") private String originPlace; @NotNull @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky") private String destinationPlace; @NotNull @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date front", example = "2019-12-18") private LocalDate outboundPartialDate; @JsonFormat(pattern = "yyyy-MM-dd") @ApiModelProperty(value = "Date back", example = "2019-12-25") private LocalDate inboundPartialDate; @ApiModelProperty(value = "Min price based on all these data", example = "100") private Integer minPrice; @ApiModelProperty(value = "Response which contains all the need info about min price flight") private FlightPricesDto flightPricesDto; }
- @Email - checks for the correct spelling of e-mail;
- @NotNull - checks that the variable should not be empty.
Application testing
In the article I will not describe testing. However, there are tests on the project , and you can view and study them yourself. Moreover, if there are any questions, you can ask them here in the comments: I will be happy to answer them.Development plans
The project is already there and I plan to work on it further. In the near future I want to do the following:- write a separate client for Skyscanner Flight Search as a library so that you can use it as a dependency not only in this project, but also in others;
- transfer to PostgreSQL so that data on Heroku is not lost when the application is stopped. This will make it more stable;
- create controllers for the client data that is supported by it. For example for Places, Currencies, Countries;
- expand search functionality. There are many more options out there;
- I'm waiting for suggestions from the community.
conclusions
Writing a web application with a REST API based on Spring Boot and the ecosystem as a whole is not as difficult as it might seem. Yes, there are nuances to be aware of. To clarify everything related to spring, I recommend reading Spring in Action 5th edition . After this book, it will become clearer what is happening here. PS it can be found in VK for free.useful links
All the data that I used when writing the project and just useful links to understand what it would be good to study:- Project link: flights-monitoring .
- Link to the deployed project on heroku .
- Sptring Initializr is a quick way to build a project with the right configurations and dependencies. Link to the generated project .
- Skyscanner Flight Search is an open API for getting flight data.
- Habr: Introduction to Spring Boot: Building a Simple Java REST API .
- CodeGym: An Introduction to the Jackson Framework .
- CodeGym: Project Lombok, or declaring war on the boilerplate .
- Rapidapi: Skyscanner Flight Search API(Java) .
- Wiki: POJO .
- Spring Boot With H2 database .
- Solving problems with Gmail for sending emails.
- Spring Boot - how to send email via SMTP.
- scheduling tasks.
- Setting Up Swagger 2 with a Spring REST API.
GO TO FULL VERSION