JavaRush /Java Blog /Random EN /Building an Airline Price Monitoring System: A Step-by-St...

Building an Airline Price Monitoring System: A Step-by-Step Guide [Part 3]

Published in the Random EN group
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

Building an Airline Price Monitoring System: A Step-by-Step Guide [Part 3] - 1

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.
SubscriptionController
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;
    }
The DTO has annotations from the Bean Validation API ( Habré article ), such as:
  • @Email - checks for the correct spelling of e-mail;
  • @NotNull - checks that the variable should not be empty.
And that’s it… The entire project can be viewed on GitHub flights-monitoring . What's more, it's currently deployed on Heroku and can be viewed here . PS do not be surprised that the first request is loaded for a long time. This account is free, and therefore, after 30 minutes of inactivity, heroku stops the application and, when requested, it deploys it back. Therefore, the data is not saved, because when the H2 stops, it kills all the data.

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. Building an Airline Price Monitoring System: A Step-by-Step Guide [Part 3] - 2

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:
  1. Project link: flights-monitoring .
  2. Link to the deployed project on heroku .
  3. Sptring Initializr is a quick way to build a project with the right configurations and dependencies. Link to the generated project .
  4. Skyscanner Flight Search is an open API for getting flight data.
  5. Habr: Introduction to Spring Boot: Building a Simple Java REST API .
  6. CodeGym: An Introduction to the Jackson Framework .
  7. CodeGym: Project Lombok, or declaring war on the boilerplate .
  8. Rapidapi: Skyscanner Flight Search API(Java) .
  9. Wiki: POJO .
  10. Spring Boot With H2 database .
  11. Solving problems with Gmail for sending emails.
  12. Spring Boot - how to send email via SMTP.
  13. scheduling tasks.
  14. Setting Up Swagger 2 with a Spring REST API.
See also my other articles:
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION