Skip to content

Commit f497da4

Browse files
google-labs-jules[bot]arii
authored andcommitted
refactor: Standardize API errors and add .nvmrc
- Standardizes error responses across all critical API routes by consistently using the ApiError class. - Adds a .nvmrc file to enforce a consistent Node.js version across development environments. - Removes commented-out code from the API routes.
1 parent 24455a4 commit f497da4

6 files changed

Lines changed: 40 additions & 19 deletions

File tree

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.21.1

app/api/internal/clear-token/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApiError } from '@/lib/errors'
12
import * as fs from 'fs'
23
import { NextResponse } from 'next/server'
34
import * as path from 'path'
@@ -30,6 +31,12 @@ export async function POST(_req: Request) {
3031
})
3132
}
3233
} catch (error) {
34+
if (error instanceof ApiError) {
35+
return NextResponse.json(
36+
{ error: error.message },
37+
{ status: error.statusCode }
38+
)
39+
}
3340
console.error('[API /clear-token] Error clearing token file:', error)
3441
return NextResponse.json(
3542
{

app/api/internal/token-delivery/route.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApiError } from '@/lib/errors'
12
import fs from 'fs'
23
import { NextRequest, NextResponse } from 'next/server'
34
import path from 'path'
@@ -16,7 +17,7 @@ export async function POST(req: NextRequest) {
1617
const secretHeader = req.headers.get('x-internal-token-secret') || ''
1718
const expected = process.env.INTERNAL_TOKEN_DELIVERY_SECRET || ''
1819
if (expected && secretHeader !== expected) {
19-
return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
20+
throw new ApiError(401, 'Unauthorized')
2021
}
2122

2223
const payload = await req.json()
@@ -34,6 +35,12 @@ export async function POST(req: NextRequest) {
3435
console.log('Received token-delivery:', payload.sub ?? payload.provider)
3536
return NextResponse.json({ ok: true })
3637
} catch (err) {
38+
if (err instanceof ApiError) {
39+
return NextResponse.json(
40+
{ error: err.message },
41+
{ status: err.statusCode }
42+
)
43+
}
3744
console.error('token-delivery error:', err)
3845
return NextResponse.json({ error: 'server_error' }, { status: 500 })
3946
}

app/api/spotify/control/route.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { getServerSession } from 'next-auth/next'
88
import { NextRequest, NextResponse } from 'next/server'
99
import { authOptions } from '@/lib/auth'
10+
import { ApiError } from '@/lib/errors'
1011
import { withValidation } from '@/lib/middleware/validation'
1112
import { spotifyControlSchema } from '@/lib/validation/schemas'
1213
import { z } from 'zod'
@@ -18,10 +19,7 @@ const handler = async (
1819
const session = await getServerSession(authOptions)
1920

2021
if (!session || !session.accessToken) {
21-
return NextResponse.json(
22-
{ error: 'Authorization required' },
23-
{ status: 401 }
24-
)
22+
throw new ApiError(401, 'Authorization required')
2523
}
2624

2725
const { command } = body
@@ -74,6 +72,12 @@ const handler = async (
7472
{ status: response.status }
7573
)
7674
} catch (error) {
75+
if (error instanceof ApiError) {
76+
return NextResponse.json(
77+
{ error: error.message },
78+
{ status: error.statusCode }
79+
)
80+
}
7781
console.error('REST control failed:', error)
7882
return NextResponse.json(
7983
{ error: 'Internal server error processing command.' },

app/api/spotify/devices/route.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { authOptions } from '@/lib/auth'
2+
import { ApiError } from '@/lib/errors'
23
import { getServerSession } from 'next-auth/next'
34
import { NextResponse } from 'next/server'
45

@@ -19,11 +20,7 @@ export async function GET(_req: Request) {
1920

2021
// 2. Check if the session and token exist.
2122
if (!session || !session.accessToken) {
22-
console.error('[API /devices] No session or access token found.')
23-
return NextResponse.json(
24-
{ error: 'Not authenticated or token is missing.' },
25-
{ status: 401 }
26-
)
23+
throw new ApiError(401, 'Not authenticated or token is missing.')
2724
}
2825

2926
// 3. Fetch devices from Spotify API.
@@ -50,6 +47,12 @@ export async function GET(_req: Request) {
5047
const data = await response.json()
5148
return NextResponse.json(data.devices || [])
5249
} catch (error) {
50+
if (error instanceof ApiError) {
51+
return NextResponse.json(
52+
{ error: error.message },
53+
{ status: error.statusCode }
54+
)
55+
}
5356
const message =
5457
error instanceof Error ? error.message : 'An unknown error occurred.'
5558
console.error(`[API /devices] Internal Server Error: ${message}`)

app/api/spotify/playlists/search/route.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// This endpoint is used by the PlaylistSelector component to search for popular playlists
44

55
import { authOptions } from '@/lib/auth'
6+
import { ApiError } from '@/lib/errors'
67
import { SimplifiedPlaylist, SpotifyApi } from '@spotify/web-api-ts-sdk'
78
import { getServerSession } from 'next-auth/next'
89
import { NextRequest, NextResponse } from 'next/server'
@@ -23,11 +24,7 @@ export async function GET(req: NextRequest) {
2324

2425
// 2. Check if the session and token exist.
2526
if (!session || !session.accessToken) {
26-
console.error('[API /playlists/search] No session or access token found.')
27-
return NextResponse.json(
28-
{ error: 'Not authenticated or token is missing.' },
29-
{ status: 401 }
30-
)
27+
throw new ApiError(401, 'Not authenticated or token is missing.')
3128
}
3229

3330
// 3. Get search query from URL parameters
@@ -57,10 +54,6 @@ export async function GET(req: NextRequest) {
5754
)
5855

5956
// 5. Search for playlists using the SDK
60-
// The search method searches across tracks, albums, artists, and playlists
61-
// Method signature: search(query: string, types: SearchType[], limit?: number, market?: string)
62-
// const searchResponse = await spotify.search(query, ['playlist'], 20)
63-
// Pass 'undefined' for the 3rd parameter (market) to set the 4th (limit)
6457
const searchResponse = await spotify.search(
6558
query,
6659
['playlist'],
@@ -97,6 +90,12 @@ export async function GET(req: NextRequest) {
9790

9891
return NextResponse.json({ items: searchResults })
9992
} catch (error) {
93+
if (error instanceof ApiError) {
94+
return NextResponse.json(
95+
{ error: error.message },
96+
{ status: error.statusCode }
97+
)
98+
}
10099
const message =
101100
error instanceof Error ? error.message : 'An unknown error occurred.'
102101
console.error(`[API /playlists/search] Internal Server Error: ${message}`)

0 commit comments

Comments
 (0)