Skip to content

Commit

Permalink
feat(api): add POST /users (#11)
Browse files Browse the repository at this point in the history
Resolves #6
  • Loading branch information
duongdev authored Jun 6, 2024
1 parent 292dd52 commit 413a81f
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 12 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"[json]": {
Expand Down
8 changes: 3 additions & 5 deletions apps/api/v1/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Hono } from 'hono'
import { authMiddleware } from './middlewares/auth'
import authApp from './routes/auth'
import usersApp from './routes/users'

export const hono = new Hono()

hono.use('*', authMiddleware())

hono.get('/', (c) => {
return c.json({ message: 'Hello Hono!' })
})
hono.use('*', authMiddleware)

hono.route('/auth', authApp)
hono.route('/users', usersApp)
32 changes: 30 additions & 2 deletions apps/api/v1/middlewares/auth.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
import { clerkMiddleware } from '@hono/clerk-auth'
import type { User } from '@/prisma/generated/zod'
import { clerkMiddleware, getAuth } from '@hono/clerk-auth'
import { createMiddleware } from 'hono/factory'
import { findUserById } from '../services/user.service'

export const authMiddleware = clerkMiddleware
declare module 'hono' {
interface ContextVariableMap {
user: User | null
userId: string | null
}
}

export const authMiddleware = createMiddleware(async (c, next) => {
await clerkMiddleware()(c, () => Promise.resolve())
const auth = getAuth(c)

if (!auth?.userId) {
c.set('userId', null)
c.set('user', null)
return c.json({ message: 'unauthorized' }, 401)
}

c.set('userId', auth.userId)

const user = await findUserById(auth.userId)

c.set('user', user)
c.header('x-user-id', auth.userId)

await next()
})
5 changes: 2 additions & 3 deletions apps/api/v1/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { getAuth } from '@hono/clerk-auth'
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'
import { findUserById } from '../services/user.service'

const router = new Hono()
Expand All @@ -9,13 +8,13 @@ router.get('/me', async (c) => {
const auth = getAuth(c)

if (!auth?.userId) {
throw new HTTPException(401, { message: 'unauthorized' })
return c.json({ message: 'unauthorized' }, 401)
}

const user = await findUserById(auth.userId)

if (!user) {
throw new HTTPException(401, { message: 'unauthorized' })
return c.json({ message: 'unauthorized' }, 401)
}

return c.json(user)
Expand Down
26 changes: 26 additions & 0 deletions apps/api/v1/routes/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { zValidator } from '@hono/zod-validator'
import { Hono } from 'hono'
import { createUser } from '../services/user.service'
import { zCreateUser } from '../validation'

const router = new Hono()

router.post('/', zValidator('json', zCreateUser), async (c) => {
const existingUser = c.get('user')

if (existingUser) {
return c.json({ message: 'user already exists' }, 409)
}

const userId = c.get('userId')!
const data = c.req.valid('json')

try {
const user = await createUser({ ...data, id: userId })
return c.json(user, 201)
} catch (e) {
return c.json({ userId, message: 'failed to create user', cause: e }, 500)
}
})

export default router
11 changes: 11 additions & 0 deletions apps/api/v1/services/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import prisma from '@/lib/prisma'
import type { CreateUser } from '../validation'

export async function findUserById(id: string) {
return await prisma.user.findUnique({
Expand All @@ -7,3 +8,13 @@ export async function findUserById(id: string) {
},
})
}

export async function createUser(
data: CreateUser & {
id?: string
},
) {
return await prisma.user.create({
data,
})
}
3 changes: 2 additions & 1 deletion apps/api/v1/validation/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './auth.zod'
export * from './auth.zod'
export * from './user.zod'
9 changes: 9 additions & 0 deletions apps/api/v1/validation/user.zod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { z } from 'zod'

export const zCreateUser = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string().min(3),
})

export type CreateUser = z.infer<typeof zCreateUser>

0 comments on commit 413a81f

Please sign in to comment.