Skip to content

Commit

Permalink
complete lesson
Browse files Browse the repository at this point in the history
  • Loading branch information
edisonzsq committed Mar 9, 2023
1 parent 1374db7 commit f351973
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 28 deletions.
68 changes: 52 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,58 @@ Step 1: CD to the project root directory `cart_api`

Step 2: Run `./mvnw spring-boot:run` command

## Lesson Overview (6 Mar 2023, Mon)
## Lesson Overview (9 Mar 2023, Fri)

Lesson Coverage:
- Use of `@OneToOne` and `@JoinColumn` annotation
- Start implementing new set of APIs

## New APIs

|URL|Status|Response|
|-|-|-|
|GET /carts|200|A list of records in cart table|
||404|When no records are found in cart table|
|POST /carts/add/{productId}?quantity=1|200|<p>If `productId` does not exist, create a new record with `quantity` set to 1.</p><p>When `quantity` is provided, set the quantity of the specified `productId` to the specified value.</p><p>When `quantity` is not provided, increment the quantity of the specified `productId` by 1.</p>|
||400|When the specified `productId` does not exist in the product table.
|POST /carts/decrement/{productId}|200|<p>If the specified `productId` exist and the quantity is 1, delete the record from cart table.</p><p>If the specified `productId` exist and the quantity is greater than 1, decrement the quantity by 1.</p>|
||400|When the specified `productId` does not exist in the `cart` table|
|POST /carts/clear|200|If there are records in the cart table, delete all records in the cart table|
||304|If there are no records in the cart table, do nothing.|

1. Move complex logics in `/carts` to a `@Service` class
2. Adding `User` entity
3. Use of `UserID` header as a mock authentication header

> Firebase SDK has a major shift and no longer support `signInWithEmailAndPassword` from the backend `Firebase Admin SDK` using Java.
## 1. Move complex logics to @Service class

Refer to the `add` and `decrement` methods in [CartService.java](./cart_api/src/main/java/sg/edu/ntu/cart_api/service/CartService.java) where complex logics is moved into.

Refer to [CartController.java](./cart_api/src/main/java/sg/edu/ntu/cart_api/controller/CartController.java) where the code mainly focuses on handling http request and response (status).

A custom exception called [NotFoundException.java](./cart_api/src/main/java/sg/edu/ntu/cart_api/exception/NotFoundException.java) is created to help us identify scenario where the `productId` is not found.

## 2. Adding the `User` Entity

Let's refer to our ERD again while creating our `User` Entity class.

<img src="./assets/erd.png" />

The SQL Statements required to generate the `user` table:

```sql
create table user (
id int not null auto_increment,
email varchar(255) not null,
created_at timestamp not null default current_timestamp,
primary key (id)
);

alter table cart add column user_id int;
alter table cart add constraint fk_cart_user foreign key (user_id) references user(id);
```

If you need to check all foreign keys in the DB, use the following command:

```sql
SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = 'cartdb';
```

## 3. Using `@RequestHeader` to capture value from HTTP Header

```java
public ResponseEntity<List<Cart>> findAll(@RequestHeader("user-id") int userId)
```

See [CartController.java](./cart_api/src/main/java/sg/edu/ntu/cart_api/controller/CartController.java) for full details.

We should also implement this for every methods in `CartController.java`. This will eventually affect `CartService.java` as well. All request to `/carts` must contains a `user-id` header.

End
Binary file added assets/erd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -34,16 +35,16 @@ public class CartController {
CartService service;

@RequestMapping(method=RequestMethod.GET)
public ResponseEntity<List<Cart>> findAll(){
List<Cart> cartItems = (List<Cart>)repo.findAll();
public ResponseEntity<List<Cart>> findAll(@RequestHeader("user-id") int userId){
List<Cart> cartItems = (List<Cart>)repo.findByUserId(userId);
if(cartItems.size() > 0) return ResponseEntity.ok().body(cartItems);
return ResponseEntity.notFound().build();
}

@RequestMapping(value="/add/{productId}", method=RequestMethod.POST)
public ResponseEntity add(@PathVariable int productId, @RequestParam Optional<Integer> quantity){
public ResponseEntity add(@PathVariable int productId, @RequestParam Optional<Integer> quantity, @RequestHeader("user-id") int userId){
try{
service.add(productId, quantity);
service.add(productId, quantity, userId);
return ResponseEntity.ok().build(); // When no exception is thrown means operation is successful.
}catch(NotFoundException nfe){
nfe.printStackTrace();
Expand All @@ -56,10 +57,10 @@ public ResponseEntity add(@PathVariable int productId, @RequestParam Optional<In
}

@RequestMapping(value="/decrement/{productId}", method=RequestMethod.POST)
public ResponseEntity decrement(@PathVariable int productId){
public ResponseEntity decrement(@PathVariable int productId, @RequestHeader("user-id") int userId){

try{
service.decrement(productId);
service.decrement(productId, userId);
return ResponseEntity.ok().build(); // When no exception is thrown means operation is successful.
}catch(NotFoundException nfe){
nfe.printStackTrace();
Expand Down
10 changes: 10 additions & 0 deletions cart_api/src/main/java/sg/edu/ntu/cart_api/entity/Cart.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public class Cart {
@Column(name="created_at", updatable= false)
Timestamp createdAt = new Timestamp(new Date().getTime());

@Column(name="user_id")
Integer userId;

public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}

public Integer getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Product {

@Column(name="created_at", updatable= false)
Timestamp createdAt = new Timestamp(new Date().getTime());

public Integer getId() {
return id;
}
Expand Down
49 changes: 49 additions & 0 deletions cart_api/src/main/java/sg/edu/ntu/cart_api/entity/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package sg.edu.ntu.cart_api.entity;

import java.sql.Timestamp;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Column;

@Entity
@Table(name="user")
public class User {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
Integer id;

String email;

@Column(name="created_at", updatable= false)
Timestamp createdAt = new Timestamp(new Date().getTime());

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Timestamp getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sg.edu.ntu.cart_api.repository;

import java.util.Optional;
import java.util.List;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
Expand All @@ -10,5 +11,7 @@
@Repository
public interface CartRepository extends CrudRepository<Cart, Integer> {

Optional<Cart> findByProductId(int productId);
Optional<Cart> findByProductIdAndUserId(int productId, int userId);

List<Cart> findByUserId(int userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public class CartService {
@Autowired
ProductRepository productRepo;

public void add(int productId, Optional<Integer> quantity) throws NotFoundException {
Optional<Cart> optionalCartItem = repo.findByProductId(productId);
public void add(int productId, Optional<Integer> quantity, int userId) throws NotFoundException {
Optional<Cart> optionalCartItem = repo.findByProductIdAndUserId(productId, userId);

if(optionalCartItem.isPresent()){

Expand All @@ -39,15 +39,16 @@ public void add(int productId, Optional<Integer> quantity) throws NotFoundExcept
Cart cartItem = new Cart();
cartItem.setProduct(product);
cartItem.setQuantity(quantity.orElseGet(() -> 1));
cartItem.setUserId(userId);
repo.save(cartItem);
}else{
throw new NotFoundException("Product ID not found");
}
}
}

public void decrement(int productId) throws NotFoundException{
Optional<Cart> optionalCartItem = repo.findByProductId(productId);
public void decrement(int productId, int userId) throws NotFoundException{
Optional<Cart> optionalCartItem = repo.findByProductIdAndUserId(productId, userId);
if(optionalCartItem.isPresent()){

int currentQuantity = 0;
Expand Down

0 comments on commit f351973

Please sign in to comment.