Skip to content

Commit

Permalink
Merge pull request #194 from TECH-C-LT/refactor/api-error-handring
Browse files Browse the repository at this point in the history
Refactor/api error handring
  • Loading branch information
R1013-T committed Aug 17, 2024
2 parents 5829790 + 41bbee6 commit 9a59c66
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 133 deletions.
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@peace-net/shared": "workspace:*",
"@supabase/supabase-js": "^2.45.0",
"ai": "^3.3.7",
"hono": "^4.5.5",
"hono": "^4.5.6",
"openai": "^4.55.9",
"zod": "^3.23.8"
},
Expand Down
47 changes: 19 additions & 28 deletions apps/api/src/features/guardians/guardian.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NotImplementedError } from '@peace-net/shared/core/error'
import { GuardianTextDTO } from '@peace-net/shared/types/guardian'
import { handleError } from '@peace-net/shared/utils/error-handler'
import { Context } from 'hono'

import { IGuardianUseCase } from '~/features/guardians/guardian.usecase'
Expand All @@ -21,35 +20,27 @@ export class GuardianController {
constructor(private guardianUseCase: IGuardianUseCase) {}

async guardianText(c: Context) {
try {
const dto = (await c.req.json()) as GuardianTextDTO

const userId = c.get('userId') as string
const apiKeyId = c.get('apiKeyId') as string

const result = await this.guardianUseCase.guardianText({
...dto,
userId,
apiKeyId,
})

if (!result.ok) {
throw result.error
}

return c.json(result.value)
} catch (error) {
return handleError(c, error)
const dto = (await c.req.json()) as GuardianTextDTO

const userId = c.get('userId') as string
const apiKeyId = c.get('apiKeyId') as string
const result = await this.guardianUseCase.guardianText({
...dto,
userId,
apiKeyId,
})

if (!result.ok) {
throw result.error
}

return c.json(result.value)
}

async guardianImage(c: Context) {
try {
throw new NotImplementedError(
'Guardian API image analysis is not implemented yet',
)
} catch (error) {
return handleError(c, error)
}
// eslint-disable-next-line no-unused-vars
async guardianImage(_c: Context) {
throw new NotImplementedError(
'Guardian API image analysis is not implemented yet',
)
}
}
55 changes: 30 additions & 25 deletions apps/api/src/features/guardians/guardian.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AnthropicProvider } from '@ai-sdk/anthropic'
import { GoogleGenerativeAIProvider } from '@ai-sdk/google'
import { OpenAIProvider } from '@ai-sdk/openai'
import { InternalServerError } from '@peace-net/shared/core/error'
import { categoryScoresSchema } from '@peace-net/shared/schemas/guardian'
import type { CategoryScores, Models } from '@peace-net/shared/types/guardian'
import { generateObject } from 'ai'
Expand Down Expand Up @@ -83,31 +84,35 @@ export class GuardianService implements IGuardianService {
text: string,
selectedModel: Models,
): Promise<CategoryScores> {
let model
switch (selectedModel) {
case 'gpt-4o-mini':
model = this.openai('gpt-4o-mini')
break
case 'claude-3-haiku':
model = this.anthropic('claude-3-haiku-20240307')
break
case 'gemini-1.5-flash':
model = this.google('models/gemini-1.5-flash')
break
default:
model = this.openai('gpt-4o-mini')
break
}

const { object } = await generateObject({
model,
schema: z.object({ category_scores: categoryScoresSchema }),
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `分析するテキスト: ${text}` },
],
})
try {
let model
switch (selectedModel) {
case 'gpt-4o-mini':
model = this.openai('gpt-4o-mini')
break
case 'claude-3-haiku':
model = this.anthropic('claude-3-haiku-20240307')
break
case 'gemini-1.5-flash':
model = this.google('models/gemini-1.5-flash')
break
default:
model = this.openai('gpt-4o-mini')
break
}

return object.category_scores
const { object } = await generateObject({
model,
schema: z.object({ category_scores: categoryScoresSchema }),
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `分析するテキスト: ${text}` },
],
})
return object.category_scores
} catch (error) {
console.error(error)
throw new InternalServerError('Failed to analyze text')
}
}
}
29 changes: 12 additions & 17 deletions apps/api/src/features/sunshines/sunshine.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { SunshineTextDTO } from '@peace-net/shared/types/sunshine'
import { handleError } from '@peace-net/shared/utils/error-handler'
import { Context } from 'hono'

import { ISunshineUseCase } from '~/features/sunshines/sunshine.usecase'
Expand All @@ -8,25 +7,21 @@ export class SunshineController {
constructor(private sunshineUseCase: ISunshineUseCase) {}

async sunshineText(c: Context) {
try {
const dto = (await c.req.json()) as SunshineTextDTO
const dto = (await c.req.json()) as SunshineTextDTO

const userId = c.get('userId') as string
const apiKeyId = c.get('apiKeyId') as string
const userId = c.get('userId') as string
const apiKeyId = c.get('apiKeyId') as string

const result = await this.sunshineUseCase.sunshineText({
...dto,
userId,
apiKeyId,
})
const result = await this.sunshineUseCase.sunshineText({
...dto,
userId,
apiKeyId,
})

if (!result.ok) {
throw result.error
}

return c.json(result.value)
} catch (error) {
return handleError(c, error)
if (!result.ok) {
throw result.error
}

return c.json(result.value)
}
}
26 changes: 16 additions & 10 deletions apps/api/src/features/sunshines/sunshine.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OpenAIProvider } from '@ai-sdk/openai'
import { InternalServerError } from '@peace-net/shared/core/error'
import { SunshineResult } from '@peace-net/shared/types/sunshine'
import { generateObject } from 'ai'
import { z } from 'zod'
Expand Down Expand Up @@ -39,15 +40,20 @@ export class SunshineService implements ISunshineService {
constructor(private openai: OpenAIProvider) {}

async sunshineText(text: string): Promise<SunshineResult> {
const { object } = await generateObject({
model: this.openai('gpt-4o-mini'),
schema: z.object({ text: z.string() }),
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `変換するテキスト: ${text}` },
],
})

return object
try {
const { object } = await generateObject({
model: this.openai('gpt-4o-mini'),
schema: z.object({ text: z.string() }),
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `変換するテキスト: ${text}` },
],
})

return object
} catch (error) {
console.error(error)
throw new InternalServerError('Failed to generate object')
}
}
}
32 changes: 14 additions & 18 deletions apps/api/src/middleware/authenticate.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,23 @@ export const authenticateMiddleware = async (c: Context) => {
throw new UnauthorizedError('API key required')
}

try {
const result = await new ApiKeyUsecase(
new ApiKeyService(
new ApiKeyRepository(
SupabaseClient(
getEnv(c).SUPABASE_URL,
getEnv(c).SUPABASE_SERVICE_ROLE_KEY,
),
const result = await new ApiKeyUsecase(
new ApiKeyService(
new ApiKeyRepository(
SupabaseClient(
getEnv(c).SUPABASE_URL,
getEnv(c).SUPABASE_SERVICE_ROLE_KEY,
),
),
).verifyApiKey({ apiKey, encryptionKey: getEnv(c).ENCRYPTION_KEY })
),
).verifyApiKey({ apiKey, encryptionKey: getEnv(c).ENCRYPTION_KEY })

if (!result.ok) {
throw result.error
}
if (!result.ok) {
throw result.error
}

c.set('apiKeyId', result.value.apiKeyId)
c.set('userId', result.value.userId)
c.set('apiKeyId', result.value.apiKeyId)
c.set('userId', result.value.userId)

return
} catch (error: any) {
throw new UnauthorizedError(error?.message || 'Invalid API key')
}
return
}
30 changes: 13 additions & 17 deletions apps/api/src/middleware/usage.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,22 @@ import { UserPlanService } from '~/features/userPlans/userPlan.service'
import { SupabaseClient } from '~/libs/supabase'

export const usageMiddleware = async (c: Context, next: Next) => {
try {
const userId = c.get('userId') as string
const userId = c.get('userId') as string

const result = await new UsageUsecase(
new UserPlanService(
new UserPlanRepository(
SupabaseClient(
getEnv(c).SUPABASE_URL,
getEnv(c).SUPABASE_SERVICE_ROLE_KEY,
),
const result = await new UsageUsecase(
new UserPlanService(
new UserPlanRepository(
SupabaseClient(
getEnv(c).SUPABASE_URL,
getEnv(c).SUPABASE_SERVICE_ROLE_KEY,
),
),
).checkUsage({ userId })
),
).checkUsage({ userId })

if (!result.ok) {
throw new UsageLimitExceededError(result.error.message)
}

return next()
} catch (error: any) {
throw new UsageLimitExceededError(error.message)
if (!result.ok) {
throw new UsageLimitExceededError(result.error.message)
}

return next()
}
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"dependencies": {
"clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"hono": "^4.5.3",
"hono": "^4.5.6",
"tailwind-merge": "^2.4.0",
"zod": "^3.23.8"
}
Expand Down
26 changes: 10 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9a59c66

Please sign in to comment.