-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f3d37d7
Showing
49 changed files
with
1,003 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
# rent-information-service | ||
|
||
## Authentication | ||
One user is available. | ||
|
||
**Username**: `rokas` | ||
|
||
**Password**: `rokas1` | ||
|
||
## API calls | ||
### List products | ||
Fetches products available to rent. | ||
|
||
* **URL** | ||
|
||
/api/v1/products | ||
|
||
* **Method** | ||
|
||
`GET` | ||
|
||
* **URL Params** | ||
|
||
N/A | ||
|
||
* **Data Params** | ||
|
||
N/A | ||
|
||
* **Success Response** | ||
|
||
* **Code**: 200 OK | ||
* **Content**: `[{"id":1,"title":"Skis"},{"id":2,"title":"Snowboard"},...]` | ||
|
||
|
||
* **Error Response** | ||
|
||
* **Code**: 401 UNAUTHORIZED | ||
|
||
|
||
* **Sample Call** | ||
|
||
``` | ||
curl --location --request GET 'http://localhost:8080/api/v1/products' \ | ||
--header 'Authorization: Basic cm9rYXM6cm9rYXMx' \ | ||
--header 'Cookie: JSESSIONID=748E420446F0264E69924105E66B699E' | ||
``` | ||
|
||
|
||
### Show product details | ||
Fetches individual product details. | ||
|
||
* **URL** | ||
|
||
/api/v1/details | ||
|
||
* **Method** | ||
|
||
`GET` | ||
|
||
* **URL Params** | ||
|
||
**Required**: | ||
|
||
``id=[integer]`` | ||
|
||
* **Data Params** | ||
|
||
N/A | ||
|
||
* **Success Response** | ||
|
||
* **Code**: 200 OK | ||
* **Content**: `{"id":1,"title":"Skis","commitmentMonths":[0,3,6]}` | ||
|
||
|
||
* **Error Response** | ||
|
||
* **Code**: 400 BAD_REQUEST | ||
|
||
* **Code**: 401 UNAUTHORIZED | ||
|
||
* **Code**: 404 NOT_FOUND | ||
|
||
|
||
* **Sample Call** | ||
|
||
``` | ||
curl --location --request GET 'http://localhost:8080/api/v1/details?id=1' \ | ||
--header 'Authorization: Basic cm9rYXM6cm9rYXMx' \ | ||
--header 'Cookie: JSESSIONID=748E420446F0264E69924105E66B699E' | ||
``` | ||
|
||
|
||
### Delete product | ||
Deletes a product. | ||
|
||
* **URL** | ||
|
||
/api/v1/delete | ||
|
||
* **Method** | ||
|
||
`GET` | ||
|
||
* **URL Params** | ||
|
||
**Required**: | ||
|
||
``id=[integer]`` | ||
|
||
* **Data Params** | ||
|
||
N/A | ||
|
||
* **Success Response** | ||
|
||
* **Code**: 200 OK | ||
|
||
|
||
* **Error Response** | ||
|
||
* **Code**: 400 BAD_REQUEST | ||
|
||
* **Code**: 401 UNAUTHORIZED | ||
|
||
* **Code**: 404 NOT_FOUND | ||
|
||
|
||
* **Sample Call** | ||
|
||
``` | ||
curl --location --request GET 'http://localhost:8080/api/v1/delete?id=1' \ | ||
--header 'Authorization: Basic cm9rYXM6cm9rYXMx' \ | ||
--header 'Cookie: JSESSIONID=A3E8A8255D27A1501BAF8BBCA9157DEA' | ||
``` | ||
|
||
|
||
### Calculate order price | ||
Fetches order price depending on product, commitment, months of return. | ||
|
||
* **URL** | ||
|
||
/api/v1/price | ||
|
||
* **Method** | ||
|
||
`POST` | ||
|
||
* **URL Params** | ||
|
||
N/A | ||
|
||
* **Data Params** | ||
|
||
JSON format. | ||
|
||
**Required**: | ||
|
||
`"id":[integer]` | ||
|
||
**Optional**: | ||
|
||
`"commitment":[integer]`. Must be one of {3, 6}. | ||
|
||
`"returnMonths":[integer]`. Must be greater than or equal to 0. | ||
|
||
* **Success Response** | ||
|
||
* **Code**: 200 OK | ||
* **Content**: `70.0` | ||
|
||
|
||
* **Error Response** | ||
|
||
* **Code**: 400 BAD_REQUEST | ||
|
||
* **Code**: 401 UNAUTHORIZED | ||
|
||
* **Code**: 404 NOT_FOUND | ||
|
||
|
||
* **Sample Call** | ||
|
||
``` | ||
curl --location --request POST 'http://localhost:8080/api/v1/price' \ | ||
--header 'Authorization: Basic cm9rYXM6cm9rYXMx' \ | ||
--header 'Content-Type: application/json' \ | ||
--header 'Cookie: JSESSIONID=748E420446F0264E69924105E66B699E' \ | ||
--data-raw '{"id":1,"commitment":3,"returnMonths":1}' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Rental Store Mock API | ||
REST API made with Spring Boot (web, JPA, validation, cache, security), H2 database, Flyway migration, Docker, JUnit and Mockito tests, Lombok. Built on Java 11. | ||
|
||
## Use cases | ||
* API users can get a list of available equipment. | ||
* API users can choose a single product and get its details and pricing options. | ||
* API users can delete a product. | ||
* API users can calculate the total price for the chosen product, commitment and rental period. | ||
|
||
Each use case corresponds to an endpoint. Technical details and specifications of each can be found in the Documentation.md file. | ||
|
||
## Features | ||
|
||
* REST API endpoints for each use case mentioned above. | ||
* Spring Boot Validation for these endpoints. | ||
* Error codes for invalid, unauthorized or incorrect data. | ||
* Persistent H2 database. | ||
* Flyway database migrations for setting up and filling database tables. | ||
* Basic Spring Security with a single user. | ||
* Basic Spring Caching for data retrieval and cache eviction upon product deletion. | ||
* Docker script for running the generated JAR file. | ||
* JUnit unit tests for price calculations mentioned below. Mockito for mocking the database for these tests. | ||
|
||
## Sample data | ||
|
||
| Product | Price/month without commitment| Price/month for 3 month commitment | Price/month for 6 month commitment | Initial charge | Available for rent | ||
|---:|---:|---:|---:|---:|--- | ||
|Skis|$35|$30|$25|$35|Yes | ||
|Snowboard|$25|$20|$17|$25|Yes | ||
|Bike|$35|$30|$25|$35|No | ||
|Roller-blades|$17|$13|$10|$17|Yes | ||
|Skateboard|$35|$30|$25|$35|Yes | ||
|
||
## Pricing formula | ||
|
||
Commitment is a number of months that the customer chooses to rent the equipment for. It can either be 3, 6 months or no commitment. Regardless of commitment, a customer can choose to return the product at a different time in which case they would pay no commitment price. | ||
|
||
Pricing formula is as follows: | ||
|
||
*total price = initial charge + (return months * price per month, based on commitment)* | ||
|
||
For example: | ||
* User chooses a skateboard with a commitment of 6 months and chooses to return it after 2 months: | ||
* price = $35 initial charge + (2 months * $35 no commitment price) = $105 | ||
|
||
|
||
* User chooses roller-blades without a commitment and chooses to return it after 7 months: | ||
* price = $17 initial charge + (7 months * $17 no commitment price) = $136 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
FROM openjdk:11-jdk-slim | ||
ARG JAR_FILE=target/*.jar | ||
COPY ${JAR_FILE} app.jar | ||
ENTRYPOINT ["java","-jar","/app.jar"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>2.3.1.RELEASE</version> | ||
<relativePath/> | ||
</parent> | ||
<groupId>dev.rokas.task.backend</groupId> | ||
<artifactId>rent-information-service</artifactId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
<name>rent-information-service</name> | ||
<description>Boilerplate for backend application</description> | ||
<properties> | ||
<java.version>11</java.version> | ||
</properties> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-actuator</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-cache</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-jpa</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-rest</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-validation</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-security</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.security</groupId> | ||
<artifactId>spring-security-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.flywaydb</groupId> | ||
<artifactId>flyway-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<optional>true</optional> | ||
<scope>provided</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.h2database</groupId> | ||
<artifactId>h2</artifactId> | ||
<scope>runtime</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.security</groupId> | ||
<artifactId>spring-security-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.mockito</groupId> | ||
<artifactId>mockito-all</artifactId> | ||
<version>1.9.5</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-maven-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
15 changes: 15 additions & 0 deletions
15
src/main/java/dev/rokas/task/backend/RentInformationApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package dev.rokas.task.backend; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.cache.annotation.EnableCaching; | ||
|
||
@EnableCaching | ||
@SpringBootApplication | ||
public class RentInformationApplication { | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(RentInformationApplication.class, args); | ||
} | ||
|
||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/dev/rokas/task/backend/api/v1/auth/SecurityConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package dev.rokas.task.backend.api.v1.auth; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
||
@Configuration | ||
public class SecurityConfig extends WebSecurityConfigurerAdapter { | ||
|
||
@Override | ||
protected void configure(HttpSecurity http) throws Exception { | ||
http | ||
.csrf().disable() | ||
.authorizeRequests().anyRequest().authenticated() | ||
.and().headers().frameOptions().disable() | ||
.and().httpBasic(); | ||
} | ||
|
||
@Autowired | ||
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { | ||
authenticationManagerBuilder | ||
.inMemoryAuthentication() | ||
.withUser("rokas") | ||
.password(getPasswordEncoder().encode("rokas1")) | ||
.authorities("user"); | ||
} | ||
|
||
@Bean | ||
public PasswordEncoder getPasswordEncoder() { | ||
return new BCryptPasswordEncoder(); | ||
} | ||
|
||
} |
Oops, something went wrong.