diff --git a/data/backend-gateway.db b/data/backend-gateway.db
new file mode 100644
index 0000000..093ae6a
Binary files /dev/null and b/data/backend-gateway.db differ
diff --git a/pom.xml b/pom.xml
index a48234b..4b6c18c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,26 @@
17
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.xerial
+ sqlite-jdbc
+ runtime
+
+
+
+ org.hibernate.orm
+ hibernate-community-dialects
+
+
+
+ org.flywaydb
+ flyway-core
+
org.springframework.boot
spring-boot-starter-security
diff --git a/src/main/java/com/litoralregas/backend_gateway/BackendGatewayApplication.java b/src/main/java/com/litoralregas/backend_gateway/BackendGatewayApplication.java
index e462a43..ac16304 100644
--- a/src/main/java/com/litoralregas/backend_gateway/BackendGatewayApplication.java
+++ b/src/main/java/com/litoralregas/backend_gateway/BackendGatewayApplication.java
@@ -1,13 +1,15 @@
package com.litoralregas.backend_gateway;
+import com.litoralregas.backend_gateway.gateway.ProxyProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
+@EnableConfigurationProperties(ProxyProperties.class)
public class BackendGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(BackendGatewayApplication.class, args);
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/litoralregas/backend_gateway/client/ClientEntity.java b/src/main/java/com/litoralregas/backend_gateway/client/ClientEntity.java
index 6bee074..65acd1f 100644
--- a/src/main/java/com/litoralregas/backend_gateway/client/ClientEntity.java
+++ b/src/main/java/com/litoralregas/backend_gateway/client/ClientEntity.java
@@ -1,4 +1,56 @@
package com.litoralregas.backend_gateway.client;
+import jakarta.persistence.*;
+
+@Entity
+@Table(name = "clients")
public class ClientEntity {
-}
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String name;
+
+ @Column(name = "backend_base_url", nullable = false)
+ private String backendBaseUrl;
+
+ @Column(nullable = false)
+ private boolean enabled = true;
+
+ @Column(name = "created_at", nullable = false, insertable = false, updatable = false)
+ private String createdAt;
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getBackendBaseUrl() {
+ return backendBaseUrl;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public String getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setBackendBaseUrl(String backendBaseUrl) {
+ this.backendBaseUrl = backendBaseUrl;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/litoralregas/backend_gateway/client/ClientRepository.java b/src/main/java/com/litoralregas/backend_gateway/client/ClientRepository.java
index 49901f1..bb43487 100644
--- a/src/main/java/com/litoralregas/backend_gateway/client/ClientRepository.java
+++ b/src/main/java/com/litoralregas/backend_gateway/client/ClientRepository.java
@@ -1,4 +1,10 @@
package com.litoralregas.backend_gateway.client;
-public class ClientRepository {
-}
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface ClientRepository extends JpaRepository {
+
+ Optional findByName(String name);
+}
\ No newline at end of file
diff --git a/src/main/java/com/litoralregas/backend_gateway/config/WebClientConfig.java b/src/main/java/com/litoralregas/backend_gateway/config/WebClientConfig.java
index 5b9e035..bbac12d 100644
--- a/src/main/java/com/litoralregas/backend_gateway/config/WebClientConfig.java
+++ b/src/main/java/com/litoralregas/backend_gateway/config/WebClientConfig.java
@@ -1,14 +1,25 @@
package com.litoralregas.backend_gateway.config;
+import com.litoralregas.backend_gateway.gateway.ProxyProperties;
+import io.netty.channel.ChannelOption;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
+import reactor.netty.http.client.HttpClient;
@Configuration
public class WebClientConfig {
@Bean
- public WebClient webClient(WebClient.Builder builder) {
- return builder.build();
+ public WebClient webClient(WebClient.Builder builder, ProxyProperties proxyProperties) {
+ HttpClient httpClient = HttpClient.create()
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
+ Math.toIntExact(proxyProperties.getConnectTimeout().toMillis()))
+ .responseTimeout(proxyProperties.getResponseTimeout());
+
+ return builder
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .build();
}
}
\ No newline at end of file
diff --git a/src/main/java/com/litoralregas/backend_gateway/gateway/BackendProxyService.java b/src/main/java/com/litoralregas/backend_gateway/gateway/BackendProxyService.java
index 1b9f6e7..97c0c27 100644
--- a/src/main/java/com/litoralregas/backend_gateway/gateway/BackendProxyService.java
+++ b/src/main/java/com/litoralregas/backend_gateway/gateway/BackendProxyService.java
@@ -1,48 +1,79 @@
package com.litoralregas.backend_gateway.gateway;
import jakarta.servlet.http.HttpServletRequest;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
@Service
public class BackendProxyService {
private final WebClient webClient;
- private final String devBackendUrl;
+ private final ProxyProperties proxyProperties;
- public BackendProxyService(
- WebClient webClient,
- @Value("${gateway.dev-backend-url}") String devBackendUrl
- ) {
+ public BackendProxyService(WebClient webClient, ProxyProperties proxyProperties) {
this.webClient = webClient;
- this.devBackendUrl = devBackendUrl;
+ this.proxyProperties = proxyProperties;
}
public String getHealth() {
return webClient.get()
- .uri(devBackendUrl + "/actuator/health")
+ .uri(proxyProperties.getBackendBaseUrl() + "/actuator/health")
.retrieve()
.bodyToMono(String.class)
.block();
}
public ResponseEntity proxy(HttpServletRequest request, String body) {
+
String path = request.getRequestURI().replaceFirst("/api/backend", "");
String query = request.getQueryString();
- String targetUrl = devBackendUrl + path + (query != null ? "?" + query : "");
+ String targetUrl =
+ proxyProperties.getBackendBaseUrl()
+ + path
+ + (query != null ? "?" + query : "");
- String response = webClient
- .method(HttpMethod.valueOf(request.getMethod()))
- .uri(targetUrl)
- .bodyValue(body != null ? body : "")
- .retrieve()
- .bodyToMono(String.class)
- .block();
+ try {
+ WebClient.RequestBodySpec requestSpec = webClient
+ .method(HttpMethod.valueOf(request.getMethod()))
+ .uri(targetUrl);
- return ResponseEntity.ok(response);
+ String contentType = request.getContentType();
+
+ if (contentType != null) {
+ requestSpec.header("Content-Type", contentType);
+ }
+
+ String accept = request.getHeader("Accept");
+
+ if (accept != null) {
+ requestSpec.header("Accept", accept);
+ }
+
+ ResponseEntity response = requestSpec
+ .bodyValue(body != null ? body : "")
+ .retrieve()
+ .toEntity(String.class)
+ .block();
+
+ return ResponseEntity
+ .status(response.getStatusCode())
+ .headers(response.getHeaders())
+ .body(response.getBody());
+
+ } catch (WebClientResponseException ex) {
+ return ResponseEntity
+ .status(ex.getStatusCode())
+ .body(ex.getResponseBodyAsString());
+
+ } catch (Exception ex) {
+ return ResponseEntity
+ .status(HttpStatus.BAD_GATEWAY)
+ .body("Backend unavailable");
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/com/litoralregas/backend_gateway/gateway/ProxyProperties.java b/src/main/java/com/litoralregas/backend_gateway/gateway/ProxyProperties.java
new file mode 100644
index 0000000..2417342
--- /dev/null
+++ b/src/main/java/com/litoralregas/backend_gateway/gateway/ProxyProperties.java
@@ -0,0 +1,37 @@
+package com.litoralregas.backend_gateway.gateway;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.time.Duration;
+
+@ConfigurationProperties(prefix = "gateway.proxy")
+public class ProxyProperties {
+
+ private String backendBaseUrl;
+ private Duration connectTimeout = Duration.ofSeconds(3);
+ private Duration responseTimeout = Duration.ofSeconds(10);
+
+ public String getBackendBaseUrl() {
+ return backendBaseUrl;
+ }
+
+ public void setBackendBaseUrl(String backendBaseUrl) {
+ this.backendBaseUrl = backendBaseUrl;
+ }
+
+ public Duration getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public void setConnectTimeout(Duration connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public Duration getResponseTimeout() {
+ return responseTimeout;
+ }
+
+ public void setResponseTimeout(Duration responseTimeout) {
+ this.responseTimeout = responseTimeout;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 591f5e0..182d354 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -5,5 +5,22 @@ spring:
application:
name: backend-gateway
+ datasource:
+ url: jdbc:sqlite:./data/backend-gateway.db
+ driver-class-name: org.sqlite.JDBC
+
+ jpa:
+ database-platform: org.hibernate.community.dialect.SQLiteDialect
+ hibernate:
+ ddl-auto: none
+ show-sql: true
+
+ flyway:
+ enabled: true
+ locations: classpath:db/migration
+
gateway:
- dev-backend-url: http://10.100.1.2:18450
\ No newline at end of file
+ proxy:
+ backend-base-url: http://10.100.1.2:18450
+ connect-timeout: 3s
+ response-timeout: 10s
\ No newline at end of file
diff --git a/src/main/resources/db/migration/V1__create_clients.sql b/src/main/resources/db/migration/V1__create_clients.sql
new file mode 100644
index 0000000..d784945
--- /dev/null
+++ b/src/main/resources/db/migration/V1__create_clients.sql
@@ -0,0 +1,7 @@
+CREATE TABLE clients (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL UNIQUE,
+ backend_base_url TEXT NOT NULL,
+ enabled INTEGER NOT NULL DEFAULT 1,
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
\ No newline at end of file