skip to Main Content

Just to give a little background on the project; I’m making a Spring Boot project using Maven. I have a two microservices, one called "products" and one called "config-server" to configure the different microservices. I already have a database called "product" on my local postgres server with a table called "product", which has a bunch of items.
Unfortunately, I get the following error when I am trying to make a GET request to the http://localhost:8222/api/v1/products URL despite setting up the endpoints:

{
  "timestamp": 1436442596410,
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/api/v1/products"
}

Here are some of the relevant files:

ProductController.java:

@RestController
@RequestMapping("/api/v1/products")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService service;

    @PostMapping
    public ResponseEntity<Integer> createProduct(
            @RequestBody @Valid ProductRequest request
    ) {
        return ResponseEntity.ok(service.createProduct(request));
    }

    @PostMapping("/purchase")
    public ResponseEntity<List<ProductPurchaseResponse>> purchaseProducts(
            @RequestBody List<ProductPurchaseRequest> request
    ) {
        return ResponseEntity.ok(service.purchaseProducts(request));
    }

    @GetMapping("/{product-id}")
    public ResponseEntity<ProductResponse> findById(
            @PathVariable("product-id") Integer productId
    ) {
        return ResponseEntity.ok(service.findById(productId));
    }

    @GetMapping
    public ResponseEntity<List<ProductResponse>> findAll() {
        return ResponseEntity.ok(service.findAll());
    }
}

ProductService.java:

@Service
@RequiredArgsConstructor
public class ProductService {

    private final ProductRepository repository;
    private final ProductMapper mapper;

    public Integer createProduct(
            ProductRequest request
    ) {
        var product = mapper.toProduct(request);
        return repository.save(product).getId();
    }

    public ProductResponse findById(Integer id) {
        return repository.findById(id)
                .map(mapper::toProductResponse)
                .orElseThrow(() -> new EntityNotFoundException("Product not found with ID:: " + id));
    }

    public List<ProductResponse> findAll() {
        return repository.findAll()
                .stream()
                .map(mapper::toProductResponse)
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = ProductPurchaseException.class)
    public List<ProductPurchaseResponse> purchaseProducts(
            List<ProductPurchaseRequest> request
    ) {
        var productIds = request
                .stream()
                .map(ProductPurchaseRequest::productId)
                .toList();
        var storedProducts = repository.findAllByIdInOrderById(productIds);
        if (productIds.size() != storedProducts.size()) {
            throw new ProductPurchaseException("One or more products does not exist");
        }
        var sortedRequest = request
                .stream()
                .sorted(Comparator.comparing(ProductPurchaseRequest::productId))
                .toList();
        var purchasedProducts = new ArrayList<ProductPurchaseResponse>();
        for (int i = 0; i < storedProducts.size(); i++) {
            var product = storedProducts.get(i);
            var productRequest = sortedRequest.get(i);
            if (product.getAvailableQuantity() < productRequest.quantity()) {
                throw new ProductPurchaseException("Insufficient stock quantity for product with ID:: " + productRequest.productId());
            }
            var newAvailableQuantity = product.getAvailableQuantity() - productRequest.quantity();
            product.setAvailableQuantity(newAvailableQuantity);
            repository.save(product);
            purchasedProducts.add(mapper.toproductPurchaseResponse(product, productRequest.quantity()));
        }
        return purchasedProducts;
    }

}

Here is the ProductApplication.java, which is outside the controller file:

@SpringBootApplication
public class ProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }

}

Now in my "config-server" microservice, I have some YAML files to handle the services.

Here is the gateway-service.yml file:

server:
  port: 8222
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes: 
        - id: product-service
          uri: lb:http://PRODUCT-SERVICE
          predicates:
            - Path=/api/v1/products/**

product-service.yml:

server:
  port: 8050
spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/product
    username: XXX
    password: XXX
  jpa:
    hibernate:
      ddl-auto: validate
    database: postgresql
    database-platform: org.hibernate.dialect.PostgreSQLDialect
  flyway:
    baseline-on-migrate: true
    enabled: true
    baseline-description: "init"
    baseline-version: 0
    user: ${spring.datasource.username}
    password: ${spring.datasource.password}

And this is the application.yml file to configure the Eureka server:

eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
name:
  value: XXX
spring:
  cloud:
    config:
      override-system-properties: false

management:
  tracing:
    sampling:
      probability: 1.0

What I have tried:

I have confirmed that all the microservices are deployed in the Eureka server in port 8761:

enter image description here

I am also pretty much 100% sure that there is no error in my file hierarchy or in any of my pom.xml files.
I’ve also confirmed that the Spring Boot application is able to connect to my postgresSQL database as I was able to insert some data there using Flyway.

I would appreciate any help as to why I’m getting a 404 error when making the GET request. Thanks!

2

Answers


  1. One reason (can’t be sure without seeing the logs) could be that gateway service, doesn’t match the request to any predicate, resulting in 404.

    I think the predicate Path=/api/v1/products/** would only match requests such as /api/v1/products/foo (child routes of products) but not /api/v1/products itself. To fix that update your yml configuration to include this route as well:

    routes: 
      - id: product-service
        uri: lb:http://PRODUCT-SERVICE
        predicates:
          - Path=/api/v1/products/**
          - Path=/api/v1/products
    
    Login or Signup to reply.
  2. ı changed my dependecy. and ıt worked !

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search