Skip to content

seqeralabs/app-bootstrap

Repository files navigation

Pet Shop API - Modern Java/Micronaut Application

A comprehensive Pet Shop API demonstrating modern Java/Micronaut application best practices with multi-module structure, TypeSpec-driven API development, JWT authentication, and production-ready patterns.

πŸ—οΈ Architecture Overview

This project demonstrates a clean, maintainable multi-module architecture with API-first design:

app-bootstrap/
β”œβ”€β”€ api/                     # API definitions and model objects
β”‚   β”œβ”€β”€ src/main/java/
β”‚   β”‚   └── io/seqera/api/
β”‚   β”‚       └── model/       # Generated Request/Response DTOs
β”‚   └── spec/                # TypeSpec API definitions (source of truth)
β”‚       β”œβ”€β”€ main.tsp         # Main API specification
β”‚       └── package.json     # TypeSpec build configuration
β”œβ”€β”€ app/                     # Main application implementation
β”‚   └── src/main/
β”‚       β”œβ”€β”€ java/
β”‚       β”‚   └── io/seqera/api/
β”‚       β”‚       └── spec/    # Generated Controller interfaces
β”‚       └── groovy/
β”‚           └── io/seqera/app/
β”‚               β”œβ”€β”€ controller/  # API implementation
β”‚               β”œβ”€β”€ service/     # Business logic layer
β”‚               β”œβ”€β”€ repository/  # Data access layer
β”‚               β”œβ”€β”€ entity/      # Domain entities
β”‚               └── security/    # Authentication providers
β”œβ”€β”€ buildSrc/                # Custom Gradle plugins
└── docs/                    # API documentation

πŸš€ Key Features & Components

Application Structure

1. API Module (api/)

  • TypeSpec Source: spec/main.tsp - Single source of truth for API definitions
  • Generated Models: src/main/java/io/seqera/api/model/ - DTOs for request/response

2. Application Module (app/)

  • Generated Interfaces: src/main/java/io/seqera/api/spec/ - Controller interfaces
  • Entities: entity/Pet.groovy - Domain models with Micronaut Data annotations
  • Repositories: repository/PetRepository.groovy - Data access with multiple database support
  • Services: Business logic layer (currently handled by controllers)
  • Controllers: controller/PetController.groovy - API implementation, AuthController.groovy - Authentication handling
  • Security: security/BasicAuthenticationProvider.groovy - JWT authentication

Technology Stack

  • Framework: Micronaut 4.9.7 with Groovy
  • Authentication: JWT with HTTP-only cookies
  • Database: PostgreSQL (production) + H2 (local development)
  • Data Access: Micronaut Data JDBC with multiple dialect support
  • API Documentation: TypeSpec β†’ OpenAPI β†’ Swagger UI
  • Security: JWT-based authentication with cookie storage
  • Build: Gradle with custom convention plugins
  • Containerization: Google Jib for optimized container images

πŸ” Security Architecture

JWT Cookie Authentication

  • Authentication Provider: Custom BasicAuthenticationProvider with hardcoded credentials
  • Token Storage: HTTP-only cookies for security
  • Session Management: JWT tokens with configurable expiration
  • Protected Endpoints: All /pets/** endpoints require authentication
  • Public Endpoints: Login pages, static resources, API documentation

Security Configuration

  • Login Flow: POST to /login β†’ JWT cookie set β†’ Redirect to /dashboard
  • Logout Flow: POST to /logout β†’ Cookie cleared β†’ Redirect to /
  • Authentication Mode: Cookie-based (not session-based)
  • JWT Secret: 256-bit minimum requirement (configured in application.yml)

Default Credentials

  • Admin: username: admin, password: password
  • User: username: user, password: secret

πŸ—‚οΈ Database Architecture

Repository Pattern with Multi-Database Support

  • PostgreSQL: Production database with full SQL features
  • H2: Local development with PostgreSQL compatibility mode
  • Repository Abstraction: @Primary and @Requires(env = "h2") annotations for environment-specific implementations

Entity Design

@MappedEntity("pets")
class Pet {
    @Id @GeneratedValue Long id
    String name, species, breed, color, description
    Integer age
    Boolean isAvailable
    @DateCreated OffsetDatTime createdAt
    @DateUpdated OffsetDatTime updatedAt
}

πŸ› οΈ API Development Workflow

TypeSpec-Driven Development

  1. Define API Contract in api/spec/main.tsp:

    @route("/pets")
    interface Pets {
      @get list(): Pet[];
      @post create(@body pet: CreatePetRequest): Pet;
      @get("{id}") get(@path id: int64): Pet;
    }
  2. Generate OpenAPI Spec:

    cd api/spec
    npm install
    npm run build
    # Generates: api/spec/tsp-output/@typespec/openapi3/openapi.yaml
  3. Generate Java Code:

    ./gradlew :app:generateApiCode
    # Generates interfaces in app/src/main/java/io/seqera/api/spec/
    # Generates DTOs in api/src/main/java/io/seqera/api/model/
  4. Implement Controllers: Controllers implement the generated interfaces

API Specification Publishing

  • Swagger UI: Automatically generated at /openapi/index.html
  • OpenAPI Spec: Available at /openapi/openapi-latest.yaml
  • Versioned Specs: Versioned files like /openapi/openapi-1.0.0.yaml
  • WebJars Integration: Uses Swagger UI WebJar for consistent styling

πŸš€ Getting Started

Prerequisites

  • Java 21 (with compatibility for Java 17)
  • PostgreSQL 15+ (for production mode)
  • Node.js (for TypeSpec compilation)

Local Development Setup

1. Using H2 Database (Recommended for Development)

# Run with H2 in-memory database
./gradlew :app:run -PmicronautEnvs=h2

# Access the application
open http://localhost:8080/

2. Using PostgreSQL

# Start PostgreSQL with Docker
docker run -d \
  --name postgres-pet-shop \
  -e POSTGRES_DB=app_bootstrap \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  postgres:15

# Run the application
./gradlew :app:run

Local Configuration Implications

When running locally, the application:

  • H2 Mode: Uses in-memory database, data is lost on restart
  • PostgreSQL Mode: Requires external database, data persists
  • Authentication: Uses hardcoded credentials (not suitable for production)
  • JWT Secret: Uses default secret (should be overridden via JWT_SECRET env var)
  • CORS: Development-friendly CORS settings
  • Logging: Debug level enabled for io.seqera packages

πŸ“Š API Documentation & Usage

Access Points

Example Usage

# Login and save cookies
curl -c cookies.txt -X POST http://localhost:8080/login \
  -d "username=admin&password=password" \
  -H "Content-Type: application/x-www-form-urlencoded"

# Access protected Pet API
curl -b cookies.txt http://localhost:8080/pets

# Create a new pet
curl -b cookies.txt -X POST http://localhost:8080/pets \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Fluffy",
    "species": "Cat",
    "breed": "Persian",
    "age": 3,
    "color": "White",
    "description": "Friendly and playful"
  }'

πŸ§ͺ Development & Testing

Code Generation & Documentation

API Documentation Generation

# Generate OpenAPI spec from TypeSpec source
./gradlew :api:generateOpenApi

# Generate Swagger UI for interactive documentation
./gradlew :app:generateSwaggerUI

# Access generated documentation
open http://localhost:8080/openapi/index.html

Code Generation Workflow

# Complete API code generation pipeline (recommended)
./gradlew :app:generateApiCode

# This task performs the following steps:
# 1. Generates OpenAPI spec from TypeSpec source (api/spec/main.tsp)
# 2. Generates Java interfaces for controllers (app/src/main/java/io/seqera/api/spec/)
# 3. Generates DTOs/model classes (api/src/main/java/io/seqera/api/model/)
# 4. Copies generated code to appropriate modules

Manual Code Generation Steps

# Step 1: Generate OpenAPI specification
cd api/spec
npm install
npm run typespec:compile

# Step 2: Generate server-side interfaces and models
./gradlew :app:generateServerOpenApiApis    # Controller interfaces
./gradlew :app:generateServerOpenApiModels  # DTO classes

# Step 3: Copy generated code to proper locations
./gradlew :app:generateApiCode              # Automated copy task

Publishing API Client to Maven

Local Publishing (for testing)
# Publish API client to local Maven repository
./gradlew :api:publishToMavenLocal

# The API client will be available as:
# Group ID: io.seqera
# Artifact ID: api
# Version: [from VERSION file]
Production Publishing
# Publish to Seqera Maven repository (requires AWS credentials)
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export PUBLISH_REPO_URL=s3://maven.seqera.io/releases  # or /snapshots

# Publish the API client
./gradlew :api:publish

# Alternative: Set credentials via Gradle properties
./gradlew :api:publish \
  -Paws_access_key_id=your_access_key \
  -Paws_secret_access_key=your_secret_key \
  -Ppublish_repo_url=s3://maven.seqera.io/releases
Client Usage Example

After publishing, other projects can consume the API client:

// In consuming project's build.gradle
dependencies {
    implementation 'io.seqera:api:1.0.0'
}
// Using the generated models
import io.seqera.api.model.Pet;
import io.seqera.api.model.CreatePetRequest;

CreatePetRequest request = new CreatePetRequest()
    .name("Fluffy")
    .species("Cat")
    .breed("Persian")
    .age(3);

Generated Code Structure

api/src/main/java/io/seqera/api/
└── model/                          # Generated DTOs
    β”œβ”€β”€ Pet.java                    # Pet entity model
    β”œβ”€β”€ CreatePetRequest.java       # Create request DTO
    β”œβ”€β”€ UpdatePetRequest.java       # Update request DTO
    └── ...

app/src/main/java/io/seqera/api/
└── spec/                           # Generated controller interfaces
    β”œβ”€β”€ PetsApiSpec.java            # Pet API interface
    β”œβ”€β”€ AuthApiSpec.java            # Auth API interface
    └── ...

Development Workflow Best Practices

  1. API-First Development: Always start by updating api/spec/main.tsp
  2. Code Generation: Run ./gradlew :app:generateApiCode after TypeSpec changes
  3. Implementation: Implement generated interfaces in controller classes
  4. Testing: Test both API contracts and implementations
  5. Publishing: Publish API client for external consumers
# Typical development cycle
vim api/spec/main.tsp              # 1. Update API specification
./gradlew :app:generateApiCode     # 2. Generate code
vim app/src/main/groovy/...        # 3. Implement controllers
./gradlew test                     # 4. Run tests

Testing

# Run all tests
./gradlew test

# Run with H2 database
./gradlew :app:test

# Run specific test suites  
./gradlew :app:test --tests "*PetRepositorySpec"
./gradlew :app:test --tests "*AuthenticationSpec"

Build & Deployment

# Build application
./gradlew build

# Build container image
./gradlew :app:jibDockerBuild

# Run linting and type checking
./gradlew :app:compileGroovy

πŸ›οΈ Component Architecture

Controller Layer (controller/)

  • PetController: Implements PetsApiSpec interface from generated code
  • AuthController: Handles login/logout, dashboard rendering
  • Security Annotations: @Secured for authentication requirements

Repository Layer (repository/)

  • PetRepository: Abstract base with common CRUD operations
  • PostgresPetRepository: PostgreSQL-specific implementation
  • H2PetRepository: H2-specific implementation with @Primary for local development

Entity Layer (entity/)

  • Pet: Domain entity with Micronaut Data annotations
  • Audit Fields: @DateCreated, @DateUpdated for automatic timestamps
  • Validation: Bean validation annotations for data integrity

Security Layer (security/)

  • BasicAuthenticationProvider: Implements authentication logic
  • JWT Configuration: Cookie-based JWT with proper security headers
  • Route Protection: Security rules in application.yml

πŸ“š Additional Documentation

For detailed component documentation, see the JavaDoc in each class:

  • PetController: RESTful pet management endpoints
  • PetRepository: Data access patterns and database abstraction
  • BasicAuthenticationProvider: Authentication flow and JWT handling
  • Pet Entity: Domain model and data validation rules

πŸ”§ Configuration

Environment-Specific Configuration

  • application.yml: Base configuration
  • application-h2.yml: H2 database settings for local development
  • Security Settings: JWT configuration, authentication providers
  • Database: Multiple datasource support with environment switching

Production Considerations

  • JWT Secret: Override JWT_SECRET environment variable
  • Database: Configure proper PostgreSQL connection
  • Authentication: Replace hardcoded credentials with proper user management
  • CORS: Restrict CORS settings for production domains
  • Logging: Adjust log levels for production monitoring

About

Micronaut application bootstrap

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published