├── flow.png
├── apigateway
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ └── application.yml
│ │ └── java
│ │ │ └── tr
│ │ │ └── com
│ │ │ └── softtech
│ │ │ └── bestcommerce
│ │ │ └── apigateway
│ │ │ ├── security
│ │ │ ├── JwtDetails.java
│ │ │ ├── JwtValidator.java
│ │ │ ├── JwtConstants.java
│ │ │ └── JwtGenerator.java
│ │ │ ├── ApiGatewayApplication.java
│ │ │ └── filters
│ │ │ ├── ValidateJwtFilter.java
│ │ │ └── AddJwtFilter.java
│ └── test
│ │ └── java
│ │ └── tr
│ │ └── com
│ │ └── softtech
│ │ └── bestcommerce
│ │ └── apigateway
│ │ ├── ApiGatewayApplicationTests.java
│ │ └── security
│ │ ├── JwtGeneratorTest.java
│ │ └── JwtValidatorTest.java
├── README.md
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.properties
│ │ └── MavenWrapperDownloader.java
├── .gitignore
├── pom.xml
├── mvnw.cmd
└── mvnw
├── .idea
├── vcs.xml
├── modules.xml
├── Softtech-BestCommerce-Case.iml
└── workspace.xml
├── signin
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── data.sql
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── tr
│ │ │ └── com
│ │ │ └── softtech
│ │ │ └── bestcommerce
│ │ │ └── signin
│ │ │ ├── dtos
│ │ │ └── UserDto.java
│ │ │ ├── security
│ │ │ └── JwtConstants.java
│ │ │ ├── services
│ │ │ ├── SignInService.java
│ │ │ └── impl
│ │ │ │ └── SignInServiceImpl.java
│ │ │ ├── models
│ │ │ └── Credentials.java
│ │ │ ├── SignInApplication.java
│ │ │ ├── repositories
│ │ │ └── UserRepository.java
│ │ │ ├── entities
│ │ │ └── User.java
│ │ │ ├── exceptions
│ │ │ └── NotFoundException.java
│ │ │ ├── mappers
│ │ │ └── UserMapper.java
│ │ │ └── controllers
│ │ │ └── SignInController.java
│ └── test
│ │ └── java
│ │ └── tr
│ │ └── com
│ │ └── softtech
│ │ └── bestcommerce
│ │ └── signin
│ │ ├── SignInApplicationTests.java
│ │ ├── mappers
│ │ └── UserMapperTest.java
│ │ └── controllers
│ │ └── SignInControllerTest.java
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.properties
│ │ └── MavenWrapperDownloader.java
├── .gitignore
├── README.md
├── pom.xml
├── mvnw.cmd
└── mvnw
├── listproducts
├── src
│ ├── main
│ │ ├── java
│ │ │ └── tr
│ │ │ │ └── com
│ │ │ │ └── softtech
│ │ │ │ └── bestcommerce
│ │ │ │ └── listproducts
│ │ │ │ ├── enums
│ │ │ │ ├── PaymentOptions.java
│ │ │ │ ├── DeliveryOptions.java
│ │ │ │ └── ProductCategory.java
│ │ │ │ ├── params
│ │ │ │ └── ListProductsParams.java
│ │ │ │ ├── services
│ │ │ │ ├── ListProductsService.java
│ │ │ │ └── impl
│ │ │ │ │ └── ListProductServiceImpl.java
│ │ │ │ ├── ListProductsApplication.java
│ │ │ │ ├── repositories
│ │ │ │ └── ProductRepository.java
│ │ │ │ ├── search
│ │ │ │ └── ProductSpecification.java
│ │ │ │ ├── dtos
│ │ │ │ └── ProductDto.java
│ │ │ │ ├── exceptions
│ │ │ │ └── ConstraintViolationExceptionHandler.java
│ │ │ │ ├── mappers
│ │ │ │ ├── ProductMapper.java
│ │ │ │ └── ListProductsParamMapper.java
│ │ │ │ ├── entities
│ │ │ │ └── Product.java
│ │ │ │ └── controllers
│ │ │ │ └── ListProductsController.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ └── data.sql
│ └── test
│ │ └── java
│ │ └── tr
│ │ └── com
│ │ └── softtech
│ │ └── bestcommerce
│ │ └── listproducts
│ │ ├── ListProductsApplicationTests.java
│ │ └── mappers
│ │ ├── ListProductsParamMapperTest.java
│ │ └── ProductMapperTest.java
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.properties
│ │ └── MavenWrapperDownloader.java
├── .gitignore
├── README.md
├── pom.xml
├── mvnw.cmd
└── mvnw
├── .gitignore
├── .github
└── workflows
│ └── build.yml
├── LICENSE
├── README.md
└── BestCommerce.postman_collection.json
/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/BestCommerce-Case/master/flow.png
--------------------------------------------------------------------------------
/apigateway/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | jwt.shortExpiration=21600000
2 | jwt.longExpiration=21600000
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/signin/src/main/resources/data.sql:
--------------------------------------------------------------------------------
1 | insert into user
2 | values(10001, 'mustafa@softtech.com.tr', 'mustafa', 'pass1234');
3 |
4 | insert into user
5 | values(10002, 'ahmet@softtech.com.tr', 'ahmet', 'pass1234');
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/enums/PaymentOptions.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.enums;
2 |
3 | public enum PaymentOptions {
4 | DIRECT,
5 | INSTALLMENTS
6 | }
7 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/enums/DeliveryOptions.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.enums;
2 |
3 | public enum DeliveryOptions {
4 | NORMAL_DELIVERY,
5 | FAST_DELIVERY
6 | }
7 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/enums/ProductCategory.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.enums;
2 |
3 | public enum ProductCategory {
4 | ELECTRONICS,
5 | FASHION,
6 | FOOD
7 | }
8 |
--------------------------------------------------------------------------------
/apigateway/README.md:
--------------------------------------------------------------------------------
1 | # API Gateway
2 | - Routes requests to related service.
3 | - Creates JWT and validates JWT.
4 |
5 | ## API Properties
6 | - Server port is defined in `application.properties`.
7 | - Routing definitions can be found on `application.yml`.
--------------------------------------------------------------------------------
/signin/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/apigateway/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/listproducts/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/dtos/UserDto.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.dtos;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class UserDto {
7 |
8 | private String name;
9 | private String email;
10 | }
11 |
--------------------------------------------------------------------------------
/apigateway/src/main/java/tr/com/softtech/bestcommerce/apigateway/security/JwtDetails.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway.security;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class JwtDetails {
7 |
8 | private String subject;
9 | private long expiration;
10 | }
11 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/security/JwtConstants.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.security;
2 |
3 | public class JwtConstants {
4 |
5 | public static final String HEADER_JWT_SUBJECT = "X-JWT-Subject";
6 | public static final String HEADER_JWT_REMEMBER = "X-JWT-Remember";
7 | }
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/signin/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8081
2 |
3 | spring.datasource.url=jdbc:h2:mem:testdb
4 | spring.datasource.driverClassName=org.h2.Driver
5 | spring.datasource.username=admin
6 | spring.datasource.password=
7 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
8 | spring.h2.console.enabled=true
9 | spring.h2.console.path=/h2
--------------------------------------------------------------------------------
/signin/src/test/java/tr/com/softtech/bestcommerce/signin/SignInApplicationTests.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class SignInApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/services/SignInService.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.services;
2 |
3 | import tr.com.softtech.bestcommerce.signin.models.Credentials;
4 | import tr.com.softtech.bestcommerce.signin.dtos.UserDto;
5 |
6 | public interface SignInService {
7 |
8 | UserDto signIn(Credentials credentials);
9 | }
10 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/models/Credentials.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.models;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | @Data
7 | @NoArgsConstructor
8 | public class Credentials {
9 |
10 | private String email;
11 | private String password;
12 | private String remember;
13 | }
14 |
--------------------------------------------------------------------------------
/apigateway/src/test/java/tr/com/softtech/bestcommerce/apigateway/ApiGatewayApplicationTests.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class ApiGatewayApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/.idea/Softtech-BestCommerce-Case.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/listproducts/src/test/java/tr/com/softtech/bestcommerce/listproducts/ListProductsApplicationTests.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class ListProductsApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | .history
--------------------------------------------------------------------------------
/listproducts/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8082
2 |
3 | spring.datasource.url=jdbc:h2:mem:testdb
4 | spring.datasource.driverClassName=org.h2.Driver
5 | spring.datasource.username=admin
6 | spring.datasource.password=
7 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
8 | spring.h2.console.enabled=true
9 | spring.h2.console.path=/h2
10 |
11 | product.search.inventoryThreshold=4
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/params/ListProductsParams.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.params;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | @Data
7 | @AllArgsConstructor
8 | public class ListProductsParams {
9 |
10 | private Long userId;
11 | private int page;
12 | private int size;
13 | private String[] sort;
14 | }
15 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/SignInApplication.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SignInApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SignInApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/services/ListProductsService.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.services;
2 |
3 | import tr.com.softtech.bestcommerce.listproducts.dtos.ProductDto;
4 | import tr.com.softtech.bestcommerce.listproducts.params.ListProductsParams;
5 |
6 | import java.util.List;
7 |
8 | public interface ListProductsService {
9 |
10 | List listProducts(ListProductsParams params);
11 | }
12 |
--------------------------------------------------------------------------------
/apigateway/src/main/java/tr/com/softtech/bestcommerce/apigateway/ApiGatewayApplication.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ApiGatewayApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ApiGatewayApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/repositories/UserRepository.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.repositories;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 | import tr.com.softtech.bestcommerce.signin.entities.User;
5 |
6 | import java.util.Optional;
7 |
8 | public interface UserRepository extends JpaRepository {
9 |
10 | Optional findByEmailAndPassword(String email, String password);
11 | }
12 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/ListProductsApplication.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ListProductsApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ListProductsApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/apigateway/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | spring:
4 | cloud:
5 | gateway:
6 | routes:
7 | - id: signin
8 | uri: http://localhost:8081
9 | predicates:
10 | - Path=/v1/signin
11 | filters:
12 | - AddJwtFilter
13 | - id: products
14 | uri: http://localhost:8082
15 | predicates:
16 | - Path=/v1/products
17 | filters:
18 | - ValidateJwtFilter
19 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/entities/User.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.entities;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.Entity;
6 | import javax.persistence.GeneratedValue;
7 | import javax.persistence.Id;
8 |
9 | @Data
10 | @Entity
11 | public class User {
12 |
13 | @Id
14 | @GeneratedValue
15 | private Long id;
16 |
17 | private String name;
18 | private String email;
19 | private String password;
20 | }
21 |
--------------------------------------------------------------------------------
/signin/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/apigateway/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/listproducts/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/exceptions/NotFoundException.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.exceptions;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(HttpStatus.NOT_FOUND)
7 | public class NotFoundException extends RuntimeException {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public NotFoundException(Class clazz, String id) {
12 | super(clazz.getSimpleName() + ":" + id);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/repositories/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.repositories;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
5 | import org.springframework.stereotype.Repository;
6 | import tr.com.softtech.bestcommerce.listproducts.entities.Product;
7 |
8 | @Repository
9 | public interface ProductRepository extends
10 | JpaRepository,
11 | JpaSpecificationExecutor { }
12 |
--------------------------------------------------------------------------------
/signin/src/main/java/tr/com/softtech/bestcommerce/signin/mappers/UserMapper.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.signin.mappers;
2 |
3 | import org.springframework.stereotype.Component;
4 | import tr.com.softtech.bestcommerce.signin.dtos.UserDto;
5 | import tr.com.softtech.bestcommerce.signin.entities.User;
6 |
7 | @Component
8 | public class UserMapper {
9 |
10 | public UserDto entityToDto(User user) {
11 | if (user == null) {
12 | return null;
13 | }
14 | UserDto userDto = new UserDto();
15 | userDto.setEmail(user.getEmail());
16 | userDto.setName(user.getName());
17 | return userDto;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/search/ProductSpecification.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.search;
2 |
3 | import org.springframework.data.jpa.domain.Specification;
4 | import tr.com.softtech.bestcommerce.listproducts.entities.Product;
5 |
6 | public class ProductSpecification {
7 |
8 | public static Specification userEqualTo(Long userId) {
9 | return (root, query, cb) ->
10 | cb.equal(root.get("userId"), userId);
11 | }
12 |
13 | public static Specification inventoryGreaterThan(int num) {
14 | return (root, query, cb) ->
15 | cb.greaterThan(root.get("inventory"), num);
16 | }
17 | }
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/dtos/ProductDto.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.dtos;
2 |
3 | import lombok.Data;
4 | import tr.com.softtech.bestcommerce.listproducts.enums.DeliveryOptions;
5 | import tr.com.softtech.bestcommerce.listproducts.enums.PaymentOptions;
6 | import tr.com.softtech.bestcommerce.listproducts.enums.ProductCategory;
7 |
8 | @Data
9 | public class ProductDto {
10 |
11 | private Long id;
12 |
13 | private String name;
14 |
15 | private String description;
16 |
17 | private int inventory;
18 |
19 | private int price;
20 |
21 | private ProductCategory productCategory;
22 |
23 | private PaymentOptions paymentOptions;
24 |
25 | private DeliveryOptions deliveryOptions;
26 | }
27 |
--------------------------------------------------------------------------------
/apigateway/src/main/java/tr/com/softtech/bestcommerce/apigateway/security/JwtValidator.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway.security;
2 |
3 | import io.jsonwebtoken.JwtException;
4 | import io.jsonwebtoken.Jwts;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class JwtValidator {
10 |
11 | @Autowired
12 | private JwtConstants jwtConstants;
13 |
14 | public boolean validate(String token) {
15 | try {
16 | Jwts.parserBuilder()
17 | .setSigningKey(jwtConstants.getKey())
18 | .build()
19 | .parseClaimsJws(token);
20 | return true;
21 | } catch (JwtException e) {
22 | }
23 | return false;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Build and Tests
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 1.11
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 1.11
23 | - name: Run tests of sign in service
24 | working-directory: ./signin
25 | run: mvn test
26 | - name: Run tests of list products service
27 | working-directory: ./listproducts
28 | run: mvn test
29 | - name: Run tests of api gateway
30 | working-directory: ./apigateway
31 | run: mvn test
--------------------------------------------------------------------------------
/apigateway/src/main/java/tr/com/softtech/bestcommerce/apigateway/security/JwtConstants.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway.security;
2 |
3 | import io.jsonwebtoken.SignatureAlgorithm;
4 | import io.jsonwebtoken.security.Keys;
5 | import lombok.Getter;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.stereotype.Component;
8 |
9 | import java.security.Key;
10 |
11 | @Component
12 | public class JwtConstants {
13 |
14 | public static final String HEADER_JWT = "X-JWT";
15 | public static final String HEADER_JWT_SUBJECT = "X-JWT-Subject";
16 | public static final String HEADER_JWT_REMEMBER = "X-JWT-Remember";
17 |
18 | @Getter
19 | @Value("${jwt.shortExpiration}")
20 | private long shortExpiration;
21 |
22 | @Getter
23 | @Value("${jwt.longExpiration}")
24 | private long longExpiration;
25 |
26 | @Getter
27 | private Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
28 | }
29 |
--------------------------------------------------------------------------------
/apigateway/src/main/java/tr/com/softtech/bestcommerce/apigateway/security/JwtGenerator.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.apigateway.security;
2 |
3 | import io.jsonwebtoken.Jwts;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 |
7 | import java.util.Date;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | @Component
12 | public class JwtGenerator {
13 |
14 | @Autowired
15 | private JwtConstants jwtTokenConstants;
16 |
17 | public String generate(JwtDetails details) {
18 | Map claims = new HashMap<>();
19 | return Jwts.builder()
20 | .setClaims(claims)
21 | .setSubject(details.getSubject())
22 | .setIssuedAt(new Date())
23 | .setExpiration(new Date(new Date().getTime() + details.getExpiration()))
24 | .signWith(jwtTokenConstants.getKey())
25 | .compact();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/signin/README.md:
--------------------------------------------------------------------------------
1 | # Sign in API
2 | - Checks user credentials and return success or error http status.
3 | - Passes JWT variables on the http header.
4 | - Uses in-memory database H2.
5 |
6 | ## API Properties
7 | - Server port is defined in `application.properties`.
8 | - Sample data can be found in `data.sql`. This is executed during startup automatically.
9 |
10 | ## Sample request
11 | ```
12 | curl --location --request POST 'http://localhost:8080/v1/signin' \
13 | --header 'Content-Type: application/json' \
14 | --data-raw '{
15 | "email": "mustafa@softtech.com.tr",
16 | "password": "pass",
17 | "remember": "true"
18 | }'
19 | ```
20 |
21 | # Open points to further development
22 | - Encrypt user password
23 | - Move `JwtConstants` to a shared lib to be used in `apigateway`
24 | - Integrate this API to Authentication and Authorization solution such as KeyCloak
25 | - `id` and `email` can be added to JWT
26 |
27 | # Notes
28 | - There is no need to check password length during sign in. It should be done on sign up.
--------------------------------------------------------------------------------
/listproducts/README.md:
--------------------------------------------------------------------------------
1 | # List Products API
2 | - List authenticated merchant's products
3 | - Swagger documentation can be generated with provided annotations.
4 | - It uses in memory database H2.
5 |
6 | ## API Properties
7 | - Server port is defined in `application.properties`.
8 | - Sample data can be found in `data.sql`. This is executed during startup automatically.
9 |
10 | # Sample Requests
11 | ```shell script
12 | curl --location --request GET 'http://localhost:8080/v1/products?userId=10001&size=10&page=0&sort=price,asc,inventory,desc' \
13 | --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJnZWVldyIsImlhdCI6MTYwMDM2MDQ3MCwiZXhwIjoxNjAwMzgyMDcwfQ.kDlZ-tj6-URO8VVBLdstUwCxADHXKwo32Dbbj4pGdgA'
14 | ```
15 |
16 | # Further points to develop
17 | - Merchant/user id authorization check.
18 | - Merchant/user id can be read from JWT or if more advanced Authorzation mechanism is used, it can be retrieved from the Authorization server.
19 | - This is also can be done on API Gateway by passing/overriding userId.
20 | - Return json error when parameter validation fails.
--------------------------------------------------------------------------------
/listproducts/src/main/java/tr/com/softtech/bestcommerce/listproducts/exceptions/ConstraintViolationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package tr.com.softtech.bestcommerce.listproducts.exceptions;
2 |
3 | import org.springframework.http.HttpHeaders;
4 | import org.springframework.http.HttpStatus;
5 | import org.springframework.http.ResponseEntity;
6 | import org.springframework.web.bind.annotation.ControllerAdvice;
7 | import org.springframework.web.bind.annotation.ExceptionHandler;
8 | import org.springframework.web.context.request.WebRequest;
9 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
10 |
11 | import javax.validation.ConstraintViolationException;
12 |
13 | @ControllerAdvice
14 | public class ConstraintViolationExceptionHandler extends ResponseEntityExceptionHandler {
15 |
16 | @ExceptionHandler(value = {ConstraintViolationException.class})
17 | protected ResponseEntity