| name | add-api-endpoint |
| description | Scaffold a new REST API endpoint in odin-scout-ent following hexagonal architecture. Creates the full stack: domain model, port, service, infrastructure adapter, DTOs, and controller. Use when the user asks to add a new endpoint, API, route, or feature. |
Add API Endpoint
Scaffold all layers for a new REST endpoint in odin-scout-ent.
Prerequisites
Before starting, gather from the user:
- Resource name (e.g. "rds", "ecr", "kubernetes")
- Action (e.g. "list clusters", "fetch details", "validate resources")
- HTTP method (GET or POST — project uses POST for most)
- Input fields (what the request needs)
- Output shape (what the response returns)
- Data source (AWS SDK, OAM gRPC, or both)
Workflow
Step 1: Domain Model
Create records in com.odin.scout.domain.model:
public record NewFeatureCommand(String roleArn, String region, ...) {}
public record NewFeatureResult(...) {}
Step 2: Port Interface
Add method to existing port or create new one in com.odin.scout.domain.port:
public interface NewFeaturePort {
NewFeatureResult doAction(NewFeatureCommand command);
}
If the feature fits an existing port (e.g. NetworkDiscoveryPort, KubernetesInfrastructurePort), add the method there instead.
Step 3: Domain Service
Create or extend service in com.odin.scout.domain.service:
@Service
public class NewFeatureService {
private final NewFeaturePort port;
public NewFeatureService(NewFeaturePort port) {
this.port = port;
}
public NewFeatureResult doAction(String roleArn, String region) {
return port.doAction(new NewFeatureCommand(roleArn, region));
}
}
Step 4: Infrastructure Adapter
For AWS features: Add method to AwsDiscoveryAdapter (implements the port).
@Override
public NewFeatureResult doAction(NewFeatureCommand cmd) {
var credentials = credentialProviderFactory.create(cmd.roleArn());
try (var client = SomeClient.builder()
.credentialsProvider(credentials)
.region(Region.of(cmd.region()))
.build()) {
} catch (SdkException e) {
throw new AwsConnectionException("Failed to ...", e);
}
}
For OAM features: Add method to OamGrpcAccountManagerClient.
Step 5: Request/Response DTOs
Create in com.odin.scout.controller.dto.<domain>/:
public record NewFeatureRequest(
@NotBlank(message = "provisionerRoleArn is required")
@Pattern(regexp = ValidationPatterns.IAM_ROLE_ARN_REGEXP,
message = ValidationPatterns.IAM_ROLE_ARN_MESSAGE)
String provisionerRoleArn,
@NotBlank(message = "region is required")
String region
) {}
public record NewFeatureResponse(List<NewFeatureResult> items) {}
Consider extending a base request if fields overlap (e.g. NetworkBaseRequest).
Step 6: Controller
Add to existing controller or create new one:
@PostMapping("/new-action")
public ResponseEntity<NewFeatureResponse> newAction(
@Valid @RequestBody NewFeatureRequest request) {
var result = service.doAction(
request.provisionerRoleArn(), request.region());
return ResponseEntity.ok(new NewFeatureResponse(result));
}
Step 7: Update README
Add the new endpoint to README.md with request/response examples.
Step 8: Build and Run
if [ -f "pom.xml" ]; then
mvn clean package -DskipTests
elif [ -d "odin-scout-ent" ]; then
(cd odin-scout-ent && mvn clean package -DskipTests)
else
echo "Could not locate odin-scout-ent from current directory."
exit 1
fi
if [ -f "run-both-local.sh" ]; then
./run-both-local.sh
else
(cd .. && ./run-both-local.sh)
fi
Checklist