Skip to content

Commit

Permalink
Merge pull request #4 from isoppp/hono
Browse files Browse the repository at this point in the history
Hono basics
  • Loading branch information
isoppp authored Sep 24, 2024
2 parents 58f4a12 + adf12d7 commit 477c50e
Show file tree
Hide file tree
Showing 19 changed files with 1,522 additions and 2,880 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ node_modules

# Local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Testing
coverage
Expand Down
10 changes: 0 additions & 10 deletions apps/api-fastify/src/plugins/compress.ts

This file was deleted.

50 changes: 0 additions & 50 deletions apps/api-fastify/src/plugins/request-logger.ts

This file was deleted.

16 changes: 16 additions & 0 deletions apps/api-hono/.env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
APP_ENV=local
WEBAPP_URL=http://localhost:3000

# POSTGRES
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=mydb

# `openssl rand -base64 32`
SESSION_SECRET="your-secret"

DATABASE_URL="postgresql://postgres:postgres@localhost:5455/mydb?schema=public"

# GCP trace, error, logging
#GOOGLE_CLOUD_PROJECT="experimental-436413"
#GOOGLE_APPLICATION_CREDENTIALS="./src/config/google-credentials.json"
30 changes: 30 additions & 0 deletions apps/api-hono/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# dev
.yarn/
!.yarn/releases
.vscode/*
!.vscode/launch.json
!.vscode/*.code-snippets
.idea/workspace.xml
.idea/usage.statistics.xml
.idea/shelf

# deps
node_modules/

# env
.env
.env.production

# logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# misc
.DS_Store

src/config/google-credentials.json
1 change: 1 addition & 0 deletions apps/api-hono/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
save-exact=true
8 changes: 8 additions & 0 deletions apps/api-hono/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```
npm install
npm run dev
```

```
open http://localhost:3000
```
43 changes: 43 additions & 0 deletions apps/api-hono/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
"files": {
"ignore": ["dist"]
},
"json": {
"parser": {
"allowComments": true
}
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 120,
"attributePosition": "auto"
},
"javascript": {
"formatter": {
"semicolons": "asNeeded",
"quoteStyle": "single",
"jsxQuoteStyle": "single"
}
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": {
"level": "error",
"fix": "none"
}
}
}
}
}
26 changes: 26 additions & 0 deletions apps/api-hono/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "api-hono",
"scripts": {
"dev": "dotenv -e .env.local -- tsx watch src/index.ts"
},
"dependencies": {
"@google-cloud/logging-winston": "6.0.0",
"@google-cloud/opentelemetry-cloud-trace-exporter": "2.3.0",
"@hono/node-server": "1.13.1",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/instrumentation-http": "0.53.0",
"@opentelemetry/instrumentation-pino": "0.42.0",
"@opentelemetry/instrumentation-winston": "0.40.0",
"@opentelemetry/sdk-node": "0.53.0",
"@prisma/instrumentation": "5.19.1",
"chalk": "5.3.0",
"dotenv-cli": "7.4.2",
"hono": "4.6.3",
"hono-rate-limiter": "0.4.0",
"tsx": "4.19.1",
"winston": "3.14.2"
},
"devDependencies": {
"@types/node": "22.6.1"
}
}
44 changes: 44 additions & 0 deletions apps/api-hono/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { factory } from '@/lib/hono'
import { generalRateLimit } from '@/middlewares/general-rate-limit'
import { httpRedirect } from '@/middlewares/http-redirect'
import { requestSpan } from '@/middlewares/request-span'
import { serve } from '@hono/node-server'
import { compress } from 'hono/compress'
import { cors } from 'hono/cors'
import { logger as requestLogger } from 'hono/logger'
import { requestId } from 'hono/request-id'
import { secureHeaders } from 'hono/secure-headers'
import { logger } from './lib/logger'
import { initOpenTelemetry } from './lib/open-telemetry'

initOpenTelemetry()

const newApp = () => {
const app = factory.createApp()
app.use(requestSpan)
app.use(
requestLogger((message: string, ...rest: string[]) => {
logger.info(message, ...rest)
}),
)
app.use(httpRedirect)
app.use(requestId())
app.use(generalRateLimit)
app.use(cors())
app.use(secureHeaders({ removePoweredBy: true }))
app.use(compress())

app.get('/', (c) => {
return c.text('Hello Hono!')
})

return app
}

const app = newApp()
const port = 3033
logger.info(`Server is running on port ${port}`)
serve({
fetch: app.fetch,
port,
})
4 changes: 4 additions & 0 deletions apps/api-hono/src/lib/hono.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { EnvHono } from '@/types/hono-context'
import { createFactory } from 'hono/factory'

export const factory = createFactory<EnvHono>()
31 changes: 31 additions & 0 deletions apps/api-hono/src/lib/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import winston from 'winston'

// Imports the Google Cloud client library for Winston
import { LoggingWinston } from '@google-cloud/logging-winston'

const pinoLikeFormat = winston.format.printf(({ level, message, timestamp, ...metadata }) => {
const pid = process.pid
const formattedMessage = `[${timestamp}] ${level.toUpperCase()} (${pid}): ${message}`
return formattedMessage
})

export const logger = winston.createLogger({
level: 'debug',
transports: [
new winston.transports.Console({
format: winston.format.combine(
// winston.format.colorize(),
winston.format.timestamp({
format: 'HH:mm:ss.SSS',
}),
// winston.format.cli(),
pinoLikeFormat,
),
}),
process.env.GOOGLE_APPLICATION_CREDENTIALS
? new LoggingWinston({
keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
})
: null,
].filter((v) => !!v),
})
24 changes: 24 additions & 0 deletions apps/api-hono/src/lib/open-telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { TraceExporter } from '@google-cloud/opentelemetry-cloud-trace-exporter'
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'
import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino'
import { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { PrismaInstrumentation } from '@prisma/instrumentation'

export const initOpenTelemetry = () => {
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
const sdk = new NodeSDK({
traceExporter: new TraceExporter({
keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
}),
instrumentations: [
new HttpInstrumentation(),
new PinoInstrumentation(),
new WinstonInstrumentation(),
new PrismaInstrumentation(),
],
})

sdk.start()
}
}
23 changes: 23 additions & 0 deletions apps/api-hono/src/middlewares/general-rate-limit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { logger } from '@/lib/logger'
import type { EnvHono } from '@/types/hono-context'
import { getConnInfo } from '@hono/node-server/conninfo'
import { rateLimiter } from 'hono-rate-limiter'

/**
* rateLimit middleware
* limit 10 req per second per IP address
*/
export const generalRateLimit = rateLimiter<EnvHono>({
windowMs: 1000,
limit: 10,
standardHeaders: 'draft-6',
keyGenerator: (c) => {
const info = getConnInfo(c)
const key = [info.remote.address].filter((v) => !!v).join('') || 'unknown'
logger.debug(`Rate limit key: ${key}`)
return key
},
skipFailedRequests: true,
})

// TODO protect auth apis with stronger rate limit
15 changes: 15 additions & 0 deletions apps/api-hono/src/middlewares/http-redirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { factory } from '@/lib/hono'

export const httpRedirect = factory.createMiddleware(async (c, next) => {
if (c.req.method !== 'GET') return next()

const proto = c.req.header('X-Forwarded-Proto')
if (proto === 'http') {
const url = new URL(c.req.url)
url.protocol = 'https'
const newUrl = url.href
return c.redirect(newUrl)
}

await next()
})
Loading

0 comments on commit 477c50e

Please sign in to comment.