Skip to content

Commit 6e54e13

Browse files
committed
dockerize webapp and api
1 parent edc39a8 commit 6e54e13

File tree

11 files changed

+122
-9
lines changed

11 files changed

+122
-9
lines changed

api/.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
dist
3+
.next
4+
.env
5+
*.log

api/.env-dev

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
MACHINE_ID=1
2-
PORT=3000
3-
# Perhpas we should only use a domain name here instead of a full URL (with the port as it is error prone)
4-
SHORTENED_BASE_URL=http://localhost:3000
2+
PORT=3001
3+
# This is the base URL for the shortened URLs. It is used to generate the shortened URL and redirect to the original URL.
4+
# Like http://localhost:3001/aZ34PM redirecting to https://google.com
5+
SHORTENED_BASE_URL=http://localhost:3001
56
# You can set this property to false for rapid testing. It will use in-memory storage rather than pulling Redis and DynamoDB
67
USE_PERSISTENT_STORAGE=false
78
REDIS_URL=redis://localhost:6379

api/.env-docker

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
NODE_ENV=development
2+
MACHINE_ID=1
3+
PORT=3000
4+
# This is the base URL for the shortened URLs. It is used to generate the shortened URL and redirect to the original URL.
5+
# Like http://localhost:3001/aZ34PM redirecting to https://google.com
6+
SHORTENED_BASE_URL=http://localhost:3001
7+
# You can set this property to false for rapid testing. It will use in-memory storage rather than pulling Redis and DynamoDB
8+
USE_PERSISTENT_STORAGE=true
9+
REDIS_URL=redis://redis:6379
10+
# 10 minutes
11+
REDIS_TTL=600
12+
AWS_REGION=us-east-1
13+
DYNAMO_TABLE=shortUrls
14+
# for local development only
15+
DYNAMO_ENDPOINT=http://dynamodb:8000
16+
AWS_ACCESS_KEY_ID=dummy
17+
AWS_SECRET_ACCESS_KEY=dummy

api/Dockerfile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Stage 1: Build
2+
FROM node:18-alpine AS builder
3+
4+
WORKDIR /app
5+
COPY . .
6+
RUN yarn install --frozen-lockfile
7+
RUN yarn build
8+
9+
# Stage 2: Production image
10+
FROM node:18-alpine
11+
12+
WORKDIR /app
13+
ENV NODE_ENV=production
14+
15+
# Copy only what is needed for production
16+
COPY --from=builder /app/dist ./dist
17+
COPY --from=builder /app/package.json ./
18+
COPY --from=builder /app/yarn.lock ./
19+
20+
RUN yarn install --production --frozen-lockfile
21+
22+
# Create non-root user
23+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
24+
USER appuser
25+
26+
EXPOSE 3000
27+
CMD ["node", "dist/main"]

docker-compose.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
11
version: '3.8'
22

33
services:
4+
5+
api:
6+
build:
7+
context: ./api
8+
dockerfile: Dockerfile
9+
container_name: tinyurl-api
10+
restart: always
11+
ports:
12+
- "3001:3000"
13+
env_file:
14+
- ./api/.env-docker
15+
16+
webapp:
17+
build:
18+
context: ./webapp
19+
dockerfile: Dockerfile
20+
container_name: tinyurl-webapp
21+
ports:
22+
- "3000:3000"
23+
depends_on:
24+
- api
25+
env_file:
26+
- ./webapp/.env-docker
27+
428
redis:
529
image: redis:7.2.7
630
container_name: redis
731
restart: always
832
ports:
933
- "6379:6379"
10-
command: redis-server --save "" --appendonly no --maxmemory 100mb --maxmemory-policy allkeys-lru # Disable disk persistence
34+
command: redis-server --save "" --appendonly no --maxmemory 100mb --maxmemory-policy allkeys-lru # Disable disk persistence
1135
volumes:
12-
- redis_data:/data # ✅ Ensures no persistence to disk
36+
- redis_data:/data
1337
environment:
1438
- ALLOW_EMPTY_PASSWORD=yes
1539

@@ -22,7 +46,7 @@ services:
2246
depends_on:
2347
- redis
2448
environment:
25-
- REDIS_URI=redis://redis:6379 #Connect RedisInsight to Redis automatically
49+
- REDIS_URI=redis://redis:6379 #Connect RedisInsight to Redis automatically
2650

2751
dynamodb:
2852
image: amazon/dynamodb-local:2.6.0

webapp/.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
dist
3+
.next
4+
.env
5+
*.log

webapp/.env-dev

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SHORTENED_BASE_URL=http://localhost:3001

webapp/.env-docker

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SHORTENED_BASE_URL=http://api:3000

webapp/Dockerfile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Stage 1: Build
2+
FROM node:18-alpine AS builder
3+
4+
WORKDIR /app
5+
COPY . .
6+
RUN yarn install --frozen-lockfile
7+
RUN yarn build
8+
9+
# Stage 2: Production image
10+
FROM node:18-alpine
11+
12+
WORKDIR /app
13+
ENV NODE_ENV=production
14+
15+
COPY --from=builder /app/public ./public
16+
COPY --from=builder /app/.next ./.next
17+
COPY --from=builder /app/package.json ./
18+
COPY --from=builder /app/yarn.lock ./
19+
20+
RUN yarn install --production --frozen-lockfile
21+
22+
# Create non-root user
23+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
24+
USER appuser
25+
26+
EXPOSE 3000
27+
CMD ["yarn", "start"]

webapp/app/api/url-shortener/route.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ import { NextRequest, NextResponse } from 'next/server';
22
import { createShortenUrl } from '../../../lib/create-shorten-url';
33

44
export async function POST(request: NextRequest) {
5-
const { url } = await request.json().catch(() => ({})); // ✅ Simplified JSON parsing
5+
const { url } = await request.json().catch(() => ({})); //
66

77
if (typeof url !== 'string' || !url.trim()) {
88
return NextResponse.json({ error: 'Invalid URL format' }, { status: 400 });
99
}
1010

1111
try {
12-
const shortenedUrl = await createShortenUrl(url, 'http://localhost:3000');
12+
const shortenedBaseUrl = process.env.SHORTENED_BASE_URL;
13+
14+
if (!shortenedBaseUrl) {
15+
throw new Error('SHORTENED_BASE_URL not configured');
16+
}
17+
const shortenedUrl = await createShortenUrl(url, shortenedBaseUrl);
1318
return NextResponse.json({ shortenedUrl }, { status: 200 });
1419
} catch (error: any) {
1520
return NextResponse.json({ error: error.message }, { status: 400 });

0 commit comments

Comments
 (0)