Skip to content

Commit e65d516

Browse files
Merge pull request #9 from SinSo-API/dev
new updates on the API.
2 parents 1fb92a6 + 6958251 commit e65d516

8 files changed

Lines changed: 446 additions & 17 deletions

File tree

doc/openapi.spec.ts

Lines changed: 278 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ export const generateOpenAPISpec = () => {
5050
in: 'query',
5151
description: 'Sort field (example: ViewCount)',
5252
required: false,
53-
schema: { type: 'string' }
53+
schema: { type: 'string', default: 'ViewCount' }
5454
},
5555
{
5656
name: 'sortOrder',
5757
in: 'query',
58-
description: 'Sort order (example: asc/desc)',
58+
description: 'Sort order (asc/desc)',
5959
required: false,
60-
schema: { type: 'string' }
60+
schema: { type: 'string', enum: ['asc', 'desc'], default: 'desc' }
6161
}
6262
],
6363
responses: {
@@ -71,7 +71,7 @@ export const generateOpenAPISpec = () => {
7171
success: { type: 'boolean', example: true },
7272
data: {
7373
type: 'array',
74-
items: { type: 'object' }
74+
items: { $ref: '#/components/schemas/Song' }
7575
},
7676
pagination: {
7777
type: 'object',
@@ -98,6 +98,60 @@ export const generateOpenAPISpec = () => {
9898
}
9999
}
100100
},
101+
'/api/v1/songs/{id}': {
102+
get: {
103+
tags: ['Songs'],
104+
summary: 'Get song by ID',
105+
description: 'Get the details of a specific song including lyrics using the SongID. Increments the ViewCount.',
106+
parameters: [
107+
{
108+
name: 'id',
109+
in: 'path',
110+
description: 'Song ID (example: SNG-0000025)',
111+
required: true,
112+
schema: { type: 'string' }
113+
}
114+
],
115+
responses: {
116+
'200': {
117+
description: 'Song retrieved successfully',
118+
content: {
119+
'application/json': {
120+
schema: {
121+
type: 'object',
122+
properties: {
123+
success: { type: 'boolean', example: true },
124+
data: { $ref: '#/components/schemas/FullSong' }
125+
}
126+
}
127+
}
128+
}
129+
},
130+
'404': {
131+
description: 'Song not found',
132+
content: {
133+
'application/json': {
134+
schema: {
135+
type: 'object',
136+
properties: {
137+
success: { type: 'boolean', example: false },
138+
message: { type: 'string', example: 'Song not found' }
139+
}
140+
}
141+
}
142+
}
143+
},
144+
'500': {
145+
description: 'Internal server error',
146+
content: {
147+
'application/json': {
148+
schema: { $ref: '#/components/schemas/ErrorResponse' }
149+
}
150+
}
151+
}
152+
}
153+
}
154+
},
101155
'/api/v1/songs/health': {
102156
get: {
103157
tags: ['Songs'],
@@ -106,35 +160,245 @@ export const generateOpenAPISpec = () => {
106160
responses: {
107161
'200': {
108162
description: 'Service is healthy',
163+
content: {
164+
'application/json': {
165+
schema: { $ref: '#/components/schemas/HealthCheck' }
166+
}
167+
}
168+
}
169+
}
170+
}
171+
},
172+
'/api/v1/artists': {
173+
get: {
174+
tags: ['Artists'],
175+
summary: 'Get all artists',
176+
description: 'Get a paginated list of all artists with optional filters',
177+
parameters: [
178+
{
179+
name: 'page',
180+
in: 'query',
181+
description: 'Page number',
182+
required: false,
183+
schema: { type: 'string', example: '1' }
184+
},
185+
{
186+
name: 'limit',
187+
in: 'query',
188+
description: 'Items per page',
189+
required: false,
190+
schema: { type: 'string', example: '10' }
191+
},
192+
{
193+
name: 'artistId',
194+
in: 'query',
195+
description: 'Filter by artist ID (example: ART-00001)',
196+
required: false,
197+
schema: { type: 'string' }
198+
},
199+
{
200+
name: 'search',
201+
in: 'query',
202+
description: 'Search in artist names (English or Sinhala)',
203+
required: false,
204+
schema: { type: 'string' }
205+
}
206+
],
207+
responses: {
208+
'200': {
209+
description: 'Artists retrieved successfully',
109210
content: {
110211
'application/json': {
111212
schema: {
112213
type: 'object',
113214
properties: {
114-
status: { type: 'string', example: 'OK' },
115-
timestamp: { type: 'string', example: '2025-11-08T10:30:00.000Z' },
116-
environment: { type: 'string', example: 'Production' },
117-
version: { type: 'string', example: '1.0.0' }
215+
success: { type: 'boolean', example: true },
216+
data: {
217+
type: 'array',
218+
items: { $ref: '#/components/schemas/Artist' }
219+
},
220+
pagination: {
221+
type: 'object',
222+
properties: {
223+
page: { type: 'number', example: 1 },
224+
limit: { type: 'number', example: 10 },
225+
total: { type: 'number', example: 50 },
226+
totalPages: { type: 'number', example: 5 }
227+
}
228+
}
229+
}
230+
}
231+
}
232+
}
233+
},
234+
'500': {
235+
description: 'Internal server error',
236+
content: {
237+
'application/json': {
238+
schema: { $ref: '#/components/schemas/ErrorResponse' }
239+
}
240+
}
241+
}
242+
}
243+
}
244+
},
245+
'/api/v1/artists/health': {
246+
get: {
247+
tags: ['Artists'],
248+
summary: 'Check artists service health',
249+
description: 'Health check endpoint for the artists service',
250+
responses: {
251+
'200': {
252+
description: 'Service is healthy',
253+
content: {
254+
'application/json': {
255+
schema: { $ref: '#/components/schemas/HealthCheck' }
256+
}
257+
}
258+
}
259+
}
260+
}
261+
},
262+
'/api/v1/lyrics/{id}': {
263+
get: {
264+
tags: ['Lyrics'],
265+
summary: 'Get lyrics by ID',
266+
description: 'Get the lyrics for a specific song using the LyricID',
267+
parameters: [
268+
{
269+
name: 'id',
270+
in: 'path',
271+
description: 'Lyric ID (example: LYR-0000025)',
272+
required: true,
273+
schema: { type: 'string' }
274+
}
275+
],
276+
responses: {
277+
'200': {
278+
description: 'Lyrics retrieved successfully',
279+
content: {
280+
'application/json': {
281+
schema: {
282+
type: 'object',
283+
properties: {
284+
success: { type: 'boolean', example: true },
285+
data: { $ref: '#/components/schemas/Lyric' }
118286
}
119287
}
120288
}
121289
}
290+
},
291+
'404': {
292+
description: 'Lyrics not found',
293+
content: {
294+
'application/json': {
295+
schema: {
296+
type: 'object',
297+
properties: {
298+
success: { type: 'boolean', example: false },
299+
message: { type: 'string', example: 'Lyrics not found' }
300+
}
301+
}
302+
}
303+
}
304+
},
305+
'500': {
306+
description: 'Internal server error',
307+
content: {
308+
'application/json': {
309+
schema: { $ref: '#/components/schemas/ErrorResponse' }
310+
}
311+
}
312+
}
313+
}
314+
}
315+
},
316+
'/api/v1/lyrics/health': {
317+
get: {
318+
tags: ['Lyrics'],
319+
summary: 'Check lyrics service health',
320+
description: 'Health check endpoint for the lyrics service',
321+
responses: {
322+
'200': {
323+
description: 'Service is healthy',
324+
content: {
325+
'application/json': {
326+
schema: { $ref: '#/components/schemas/HealthCheck' }
327+
}
328+
}
122329
}
123330
}
124331
}
125332
}
126333
},
127334
components: {
128335
schemas: {
336+
Song: {
337+
type: 'object',
338+
properties: {
339+
ID: { type: 'number', example: 1 },
340+
SongID: { type: 'string', example: 'SNG-00001' },
341+
SongName: { type: 'string', example: 'Beautiful Song' },
342+
SongNameSinhala: { type: 'string', example: 'ලස්සන ගීතය' },
343+
ArtistID: { type: 'string', example: 'ART-00001' },
344+
Duration: { type: 'number', example: 240 },
345+
ReleaseYear: { type: 'number', example: 2024 },
346+
Composer: { type: 'string', example: 'John Doe' },
347+
Lyricist: { type: 'string', example: 'Jane Smith' },
348+
ViewCount: { type: 'number', example: 1000 }
349+
}
350+
},
351+
FullSong: {
352+
type: 'object',
353+
properties: {
354+
ID: { type: 'number', example: 1 },
355+
SongID: { type: 'string', example: 'SNG-00001' },
356+
SongName: { type: 'string', example: 'Beautiful Song' },
357+
SongNameSinhala: { type: 'string', example: 'ලස්සන ගීතය' },
358+
ArtistID: { type: 'string', example: 'ART-00001' },
359+
Duration: { type: 'number', example: 240 },
360+
ReleaseYear: { type: 'number', example: 2024 },
361+
Composer: { type: 'string', example: 'John Doe' },
362+
Lyricist: { type: 'string', example: 'Jane Smith' },
363+
LyricsContent: { type: 'string', example: 'Full lyrics in English...' },
364+
LyricsContentSinhala: { type: 'string', example: 'සම්පූර්ණ ගී පද...' },
365+
ViewCount: { type: 'number', example: 1000 }
366+
}
367+
},
368+
Artist: {
369+
type: 'object',
370+
properties: {
371+
ID: { type: 'number', example: 1 },
372+
ArtistID: { type: 'string', example: 'ART-00001' },
373+
ArtistName: { type: 'string', example: 'John Doe' },
374+
ArtistNameSinhala: { type: 'string', example: 'ජෝන් ඩෝ' }
375+
}
376+
},
377+
Lyric: {
378+
type: 'object',
379+
properties: {
380+
ID: { type: 'number', example: 1 },
381+
LyricID: { type: 'string', example: 'LYR-00001' },
382+
SongID: { type: 'string', example: 'SNG-00001' },
383+
LyricContent: { type: 'string', example: 'Full lyrics in English...' },
384+
LyricContentSinhala: { type: 'string', example: 'සම්පූර්ණ ගී පද...' }
385+
}
386+
},
387+
HealthCheck: {
388+
type: 'object',
389+
properties: {
390+
status: { type: 'string', example: 'OK' },
391+
timestamp: { type: 'string', example: '2025-11-08T10:30:00.000Z' },
392+
environment: { type: 'string', example: 'Production' },
393+
version: { type: 'string', example: '1.0.0' }
394+
}
395+
},
129396
ErrorResponse: {
130397
type: 'object',
131398
properties: {
132-
status: { type: 'number', example: 404 },
133-
code: { type: 'string', example: 'SONG_NOT_FOUND' },
134-
message: { type: 'string', example: 'Song not found' },
135-
details: { type: 'string', example: 'Song with ID SNG-9999999 does not exist' },
136-
path: { type: 'string', example: '/api/v1/songs/SNG-9999999' },
137-
timestamp: { type: 'string', example: '2025-11-08T10:30:00' }
399+
success: { type: 'boolean', example: false },
400+
message: { type: 'string', example: 'Error message' },
401+
error: { type: 'string', example: 'Detailed error information' }
138402
}
139403
}
140404
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Context } from 'hono';
2+
import { APP_VERSION } from '../metadata';
3+
import { Lyric, Env, LyricResponse } from '../models/Lyrics';
4+
5+
export class LyricsController{
6+
static checkHealth(c: Context<{ Bindings: Env }>){
7+
return c.json({
8+
status: 'OK',
9+
timestamp: new Date().toISOString(),
10+
environment: 'Production',
11+
version: APP_VERSION
12+
});
13+
}
14+
15+
static async getLyricByID(c: Context<{Bindings: Env}>){
16+
try {
17+
const lyricId = c.req.param('id');
18+
19+
const lyrics = await c.env.sinso_api_db.prepare(
20+
`SELECT * FROM Lyrics l WHERE l.LyricID = ?`
21+
).bind(lyricId).first<Lyric>();
22+
23+
if(!lyrics){
24+
return c.json({
25+
success:false,
26+
message: 'Lyrics not found'
27+
}, 404);
28+
}
29+
30+
const response: LyricResponse = {
31+
success: true,
32+
data: lyrics
33+
};
34+
35+
return c.json(response, 200);
36+
} catch (error) {
37+
return c.json({
38+
success: false,
39+
message: 'Error fetching lyrics',
40+
error: error instanceof Error ? error.message : 'Unknown error'
41+
}, 500);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)