Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/typescript-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,46 @@ jobs:
else
echo "⚠️ No Schemathesis report found"
fi

docker-build-test:
runs-on: ubuntu-latest
needs: build-and-test
permissions:
contents: read
defaults:
run:
working-directory: src/typescript

steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: |
# Copy the OpenAPI spec to the expected location for Docker build
mkdir -p docs/api
cp ../../docs/api/openapi.yaml ./docs/api/
docker build -t lamp-control-api-ts:latest .

- name: Test Docker container
run: |
# Start container in background
docker run --rm -d -p 8080:8080 --name lamp-api-test lamp-control-api-ts:latest

# Wait for container to be ready
timeout 30 bash -c 'until docker exec lamp-api-test curl -f http://127.0.0.1:8080/health > /dev/null 2>&1; do sleep 2; done'

# Test health endpoint
docker exec lamp-api-test curl -s http://127.0.0.1:8080/health | grep '"status":"ok"'

# Test API endpoint
docker exec lamp-api-test curl -s http://127.0.0.1:8080/v1/lamps | grep '"data":\[\]'

# Stop container
docker stop lamp-api-test

echo "βœ… Docker container tests passed!"

- name: Check Docker image size
run: |
echo "## Docker Image Information" >> $GITHUB_STEP_SUMMARY
docker images lamp-control-api-ts:latest --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" >> $GITHUB_STEP_SUMMARY
35 changes: 35 additions & 0 deletions src/typescript/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Ignore build artifacts
dist/
coverage/

# Ignore development files
.git
.gitignore
*.md
README.md

# Ignore test files
tests/
*.test.ts
*.test.js

# Ignore configuration files not needed in production
.eslintrc.json
.prettierrc
jest.config.js

# Ignore documentation
# docs/

# Ignore CI/CD files
.github/

# Ignore development artifacts
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
44 changes: 44 additions & 0 deletions src/typescript/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Multi-stage Docker configuration for TypeScript implementation
# Stage 1: Build environment
FROM node:22 AS build-env

WORKDIR /app

# Copy package files for dependency installation
COPY package*.json ./

# Install all dependencies using npm ci for reproducible builds
RUN npm ci

# Copy all source files
COPY src ./src
COPY tsconfig.json ./

# Create the directory structure and copy OpenAPI spec from context root
RUN mkdir -p /docs/api
COPY docs/api/openapi.yaml /docs/api/openapi.yaml

# Build the TypeScript application
RUN npm run build

# Remove development dependencies to reduce final image size
RUN npm prune --omit=dev

# Stage 2: Production runtime
FROM gcr.io/distroless/nodejs22-debian12

WORKDIR /app

# Copy built application and production dependencies from build stage
COPY --from=build-env /app/dist ./dist
COPY --from=build-env /app/node_modules ./node_modules
COPY --from=build-env /app/package*.json ./

# Copy the OpenAPI spec from build stage to the expected location
COPY --from=build-env /docs/api/openapi.yaml /docs/api/openapi.yaml

# Expose the application port
EXPOSE 8080

# Set the command to run the application
CMD ["dist/src/index.js"]
20 changes: 20 additions & 0 deletions src/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ npm run start:native

This eliminates the build step entirely while maintaining production performance.

### Docker Deployment

Build and run with Docker using the multi-stage Dockerfile:

```bash
# Build the Docker image
docker build -t lamp-control-api-ts .

# Run the container
docker run --rm -p 8080:8080 lamp-control-api-ts
```

The Docker configuration uses:
- **Multi-stage build**: Optimized for production with separate build and runtime stages
- **Node.js 22**: Build stage for compilation and dependency installation
- **Distroless runtime**: Minimal, secure production runtime environment
- **Optimized layers**: Efficient Docker layer caching for faster builds

The container exposes the API on port 8080 and includes all necessary dependencies and the OpenAPI specification.

## API Documentation

The API documentation is available at `http://localhost:8080/api-docs` when the server is running.
Expand Down
2 changes: 1 addition & 1 deletion src/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"clean": "rm -rf dist",
"dev": "tsx src/index.ts",
"dev:native": "node --experimental-strip-types src/index.ts",
"start": "node dist/index.js",
"start": "node dist/src/index.js",
"start:native": "node --experimental-strip-types src/index.ts",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
Expand Down
2 changes: 1 addition & 1 deletion src/typescript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { buildApp } from './infrastructure/app.ts';
import type { FastifyInstance } from 'fastify';

buildApp().then((server: FastifyInstance) => {
server.listen({ port: 8080 }, (err: Error | null, address: string) => {
server.listen({ port: 8080, host: '0.0.0.0' }, (err: Error | null, address: string) => {
if (err) {
server.log.error(err);
process.exit(1);
Expand Down
4 changes: 3 additions & 1 deletion src/typescript/tests/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ describe('Lamp API Endpoints', () => {
});

afterAll(async () => {
await app.close();
if (app) {
await app.close();
}
});

describe('GET /health', () => {
Expand Down
Loading