Skip to content

Commit 10eb1aa

Browse files
committed
Migrate API Gateway to standalone multi-module Gradle project
- Transform into multi-module structure with api-gateway-routing and api-gateway-main - Update to Spring Boot 3.x with Jakarta EE namespace - Migrate tests to JUnit 5 - Add HTTP contract stubs publishing from order-service-restapi - Simplify build-and-test-all.sh to publish stubs at root level Co-authored by Claude Code
1 parent 623e5f9 commit 10eb1aa

34 files changed

Lines changed: 508 additions & 110 deletions

build-and-test-all.sh

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
1717
echo ""
1818

1919
# Services that publish contract stubs (must be built first)
20-
# Format: "service-dir:submodule-with-stubs"
2120
STUB_PUBLISHERS=(
22-
"ftgo-order-service:order-service-event-publishing"
23-
"ftgo-consumer-service:consumer-service-event-publishing"
24-
"ftgo-kitchen-service:kitchen-service-event-publishing"
25-
"ftgo-accounting-service:accounting-service-command-handlers"
26-
"ftgo-restaurant-service:restaurant-service-event-publishing"
21+
"ftgo-order-service"
22+
"ftgo-consumer-service"
23+
"ftgo-kitchen-service"
24+
"ftgo-accounting-service"
25+
"ftgo-restaurant-service"
2726
)
2827

2928
# List of migrated services (add services as they are migrated)
@@ -35,16 +34,15 @@ MIGRATED_SERVICES=(
3534
"ftgo-restaurant-service"
3635
"ftgo-delivery-service"
3736
"ftgo-order-history-service"
37+
"ftgo-api-gateway"
3838
)
3939

4040
# Publish contract stubs from migrated services first
4141
echo "Publishing contract stubs from migrated services..."
42-
for entry in "${STUB_PUBLISHERS[@]}"; do
43-
service="${entry%%:*}"
44-
submodule="${entry##*:}"
45-
echo "Publishing stubs: $service ($submodule)"
42+
for service in "${STUB_PUBLISHERS[@]}"; do
43+
echo "Publishing stubs: $service"
4644
if [ -d "$service" ] && [ -f "$service/gradlew" ]; then
47-
(cd "$service" && ./gradlew ":${submodule}:publishStubsPublicationToLocalRepository" $GRADLE_ARGS)
45+
(cd "$service" && ./gradlew publishStubsPublicationToLocalRepository $GRADLE_ARGS)
4846
else
4947
echo "WARNING: Service '$service' not found or missing gradlew"
5048
fi

docs/features/upgrade-to-2026/upgrade-to-2026-plan.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,8 @@ The `ftgo-order-history-service/` directory already exists. Transform it into a
657657

658658
### Task 7.7: Verify Order History Service integration
659659

660-
- [ ] Run `./build-and-test-all.sh` and verify all seven services build
661-
- [ ] Commit all changes for Steel Thread 7
660+
- [x] Run `./build-and-test-all.sh` and verify all seven services build
661+
- [x] Commit all changes for Steel Thread 7
662662

663663
### Task 7.8: Standardize artifact coordinates for contract stubs
664664

@@ -701,30 +701,30 @@ Migrate the API Gateway as the final service.
701701

702702
The `ftgo-api-gateway/` directory already exists. Transform it into a multi-module project:
703703

704-
- [ ] Create `settings.gradle` with pluginManagement block and subproject includes:
705-
- [ ] `api-gateway-routing` - Route configurations and filters
706-
- [ ] `api-gateway-main` - Spring Boot application
707-
- [ ] Create `gradle.properties` with version properties
708-
- [ ] Create root `build.gradle` with common configuration
709-
- [ ] Create each subproject's `build.gradle`
710-
- [ ] Add Spring Cloud Gateway dependencies for Spring Boot 3.x
711-
- [ ] Generate Gradle wrapper using `gradle wrapper`
712-
- [ ] Verify `./gradlew tasks` runs successfully
704+
- [x] Create `settings.gradle` with pluginManagement block and subproject includes:
705+
- [x] `api-gateway-routing` - Route configurations and filters
706+
- [x] `api-gateway-main` - Spring Boot application
707+
- [x] Create `gradle.properties` with version properties
708+
- [x] Create root `build.gradle` with common configuration
709+
- [x] Create each subproject's `build.gradle`
710+
- [x] Add Spring Cloud Gateway dependencies for Spring Boot 3.x
711+
- [x] Generate Gradle wrapper using `gradle wrapper`
712+
- [x] Verify `./gradlew tasks` runs successfully
713713

714714
### Task 8.2: Move source files to subprojects and migrate to Spring Boot 3.x / Jakarta EE
715715

716-
- [ ] Move routing configuration to `api-gateway-routing/`
717-
- [ ] Move main class to `api-gateway-main/`
718-
- [ ] Update Spring Cloud Gateway configuration for Spring Boot 3.x
719-
- [ ] Perform `javax.*` to `jakarta.*` migration (if applicable)
720-
- [ ] Update route configurations for new service structure
716+
- [x] Move routing configuration to `api-gateway-routing/`
717+
- [x] Move main class to `api-gateway-main/`
718+
- [x] Update Spring Cloud Gateway configuration for Spring Boot 3.x
719+
- [x] Perform `javax.*` to `jakarta.*` migration (if applicable)
720+
- [x] Update route configurations for new service structure
721721

722722
### Task 8.3: Migrate API Gateway tests to appropriate subprojects
723723

724-
- [ ] Move unit tests alongside source files
725-
- [ ] Update JUnit 4 to JUnit 5
726-
- [ ] Update `javax.*` to `jakarta.*` imports
727-
- [ ] Verify `./gradlew test` passes
724+
- [x] Move unit tests alongside source files
725+
- [x] Update JUnit 4 to JUnit 5
726+
- [x] Update `javax.*` to `jakarta.*` imports
727+
- [x] Verify `./gradlew test` passes
728728
- [ ] Create integration tests (if needed)
729729
- [ ] Verify `./gradlew integrationTest` passes
730730

@@ -733,7 +733,7 @@ The `ftgo-api-gateway/` directory already exists. Transform it into a multi-modu
733733
- [ ] Update `ftgo-api-gateway/Dockerfile` for Java 17
734734
- [ ] Add `ftgo-api-gateway` to root `docker-compose.yaml`
735735
- [ ] Configure routing to all backend services
736-
- [ ] Update `build-and-test-all.sh` to include API Gateway
736+
- [x] Update `build-and-test-all.sh` to include API Gateway
737737
- [ ] Verify Docker build and service startup
738738

739739
### Task 8.5: Add end-to-end test for full system via gateway
@@ -744,8 +744,8 @@ The `ftgo-api-gateway/` directory already exists. Transform it into a multi-modu
744744

745745
### Task 8.6: Verify API Gateway integration
746746

747-
- [ ] Run `./build-and-test-all.sh` and verify all eight services build
748-
- [ ] Commit all changes for Steel Thread 8
747+
- [x] Run `./build-and-test-all.sh` and verify all eight services build
748+
- [x] Commit all changes for Steel Thread 8
749749

750750
---
751751

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
plugins {
2+
id 'org.springframework.boot'
3+
}
4+
5+
dependencies {
6+
implementation project(':api-gateway-routing')
7+
8+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
9+
implementation 'io.micrometer:micrometer-registry-prometheus'
10+
11+
testImplementation 'org.springframework.boot:spring-boot-starter-test'
12+
testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock'
13+
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner'
14+
testImplementation 'io.projectreactor:reactor-test'
15+
}
16+
17+
test {
18+
def repoDir = file("${rootProject.projectDir}/../build/repo").absolutePath
19+
systemProperty "stubrunner.repositoryRoot", "file://${repoDir}"
20+
}

ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayApplication.java renamed to ftgo-api-gateway/api-gateway-main/src/main/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayApplication.java

File renamed without changes.

ftgo-api-gateway/src/main/resources/application.properties renamed to ftgo-api-gateway/api-gateway-main/src/main/resources/application.properties

File renamed without changes.

ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayIntegrationTest.java renamed to ftgo-api-gateway/api-gateway-main/src/test/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayIntegrationTest.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,15 @@
33

44
import com.fasterxml.jackson.core.JsonProcessingException;
55
import com.fasterxml.jackson.databind.ObjectMapper;
6-
import com.github.tomakehurst.wiremock.junit.WireMockRule;
76
import net.chrisrichardson.ftgo.apiagateway.orders.OrderDetails;
87
import net.chrisrichardson.ftgo.apiagateway.proxies.OrderInfo;
9-
import org.junit.Rule;
10-
import org.junit.Test;
11-
import org.junit.runner.RunWith;
12-
import org.springframework.beans.factory.annotation.Value;
8+
import org.junit.jupiter.api.Test;
139
import org.springframework.boot.test.context.SpringBootTest;
14-
import org.springframework.boot.web.server.LocalServerPort;
10+
import org.springframework.boot.test.web.server.LocalServerPort;
1511
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
1612
import org.springframework.http.HttpStatus;
1713
import org.springframework.http.MediaType;
1814
import org.springframework.http.ResponseEntity;
19-
import org.springframework.test.context.junit4.SpringRunner;
2015
import org.springframework.web.reactive.function.BodyInserters;
2116
import org.springframework.web.reactive.function.client.WebClient;
2217

@@ -29,10 +24,9 @@
2924
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
3025
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
3126
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
32-
import static org.junit.Assert.assertEquals;
33-
import static org.junit.Assert.assertNotNull;
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
import static org.junit.jupiter.api.Assertions.assertNotNull;
3429

35-
@RunWith(SpringRunner.class)
3630
@SpringBootTest(classes = ApiGatewayIntegrationTestConfiguration.class,
3731
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
3832
properties={"order.destinations.orderServiceUrl=http://localhost:${wiremock.server.port}",
@@ -61,7 +55,7 @@ public void shouldProxyCreateOrder() {
6155

6256
ResponseEntity<String> z = client
6357
.post()
64-
.body(BodyInserters.fromObject("{}"))
58+
.body(BodyInserters.fromValue("{}"))
6559
.exchange()
6660
.flatMap(r -> r.toEntity(String.class))
6761
.block();
@@ -103,7 +97,7 @@ public void shouldProxyGetOrderDetails() throws JsonProcessingException {
10397

10498
assertNotNull(z);
10599
assertEquals(HttpStatus.OK, z.getStatusCode());
106-
assertEquals(body, expectedOrderDetails, z.getBody());
100+
assertEquals(expectedOrderDetails, z.getBody());
107101

108102
verify(getRequestedFor(urlMatching(expectedPath)));
109103

ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayIntegrationTestConfiguration.java renamed to ftgo-api-gateway/api-gateway-main/src/test/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayIntegrationTestConfiguration.java

File renamed without changes.

ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/contract/OrderServiceProxyIntegrationTest.java renamed to ftgo-api-gateway/api-gateway-main/src/test/java/net/chrisrichardson/ftgo/apiagateway/contract/OrderServiceProxyIntegrationTest.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@
44
import net.chrisrichardson.ftgo.apiagateway.proxies.OrderInfo;
55
import net.chrisrichardson.ftgo.apiagateway.proxies.OrderNotFoundException;
66
import net.chrisrichardson.ftgo.apiagateway.proxies.OrderServiceProxy;
7-
import org.junit.Before;
8-
import org.junit.Test;
9-
import org.junit.runner.RunWith;
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
109
import org.springframework.beans.factory.annotation.Value;
1110
import org.springframework.boot.test.context.SpringBootTest;
1211
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
12+
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
1313
import org.springframework.test.annotation.DirtiesContext;
14-
import org.springframework.test.context.junit4.SpringRunner;
1514
import org.springframework.web.reactive.function.client.WebClient;
1615

17-
import static org.junit.Assert.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertThrows;
1818

19-
@RunWith(SpringRunner.class)
2019
@SpringBootTest(classes=TestConfiguration.class,
2120
webEnvironment= SpringBootTest.WebEnvironment.NONE)
2221
@AutoConfigureStubRunner(ids =
23-
{"net.chrisrichardson.ftgo:ftgo-order-service"}
22+
{"net.chrisrichardson.ftgo:order-service-restapi"},
23+
stubsMode = StubRunnerProperties.StubsMode.REMOTE
2424
)
2525
@DirtiesContext
2626
public class OrderServiceProxyIntegrationTest {
2727

28-
@Value("${stubrunner.runningstubs.ftgo-order-service.port}")
28+
@Value("${stubrunner.runningstubs.order-service-restapi.port}")
2929
private int port;
3030
private OrderDestinations orderDestinations;
3131
private OrderServiceProxy orderService;
3232

33-
@Before
33+
@BeforeEach
3434
public void setUp() throws Exception {
3535
orderDestinations = new OrderDestinations();
3636
String orderServiceUrl = "http://localhost:" + port;
@@ -45,9 +45,11 @@ public void shouldVerifyExistingCustomer() {
4545
assertEquals("APPROVAL_PENDING", result.getState());
4646
}
4747

48-
@Test(expected = OrderNotFoundException.class)
48+
@Test
4949
public void shouldFailToFindMissingOrder() {
50-
orderService.findOrderById("555").block();
50+
assertThrows(OrderNotFoundException.class, () -> {
51+
orderService.findOrderById("555").block();
52+
});
5153
}
5254

5355
}

ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/contract/TestConfiguration.java renamed to ftgo-api-gateway/api-gateway-main/src/test/java/net/chrisrichardson/ftgo/apiagateway/contract/TestConfiguration.java

File renamed without changes.

ftgo-api-gateway/src/test/resources/application.properties renamed to ftgo-api-gateway/api-gateway-main/src/test/resources/application.properties

File renamed without changes.

0 commit comments

Comments
 (0)