You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

246 lines
6.1 KiB

// TODO: this file is located in the client src folder because
// otherwise, Create React App will refuse to compile it.
// Putting it in the server folder or in its own folder makes more sense.
// This file represents the API interface for Mudbase's back-end.
// Each endpoint is described by its endpoint address,
// a request structure, a response structure and
// a checking function which determines request validity.
export enum ItemType {
Song = 0,
Artist,
Album,
Tag
}
export interface ArtistDetails {
artistId: Number,
name: String,
storeLinks?: String[],
}
export function isArtistDetails(q: any): q is ArtistDetails {
return 'artistId' in q;
}
export interface TagDetails {
tagId: Number,
name: String,
parent?: TagDetails,
storeLinks?: String[],
}
export function isTagDetails(q: any): q is TagDetails {
return 'tagId' in q;
}
export interface RankingDetails {
rankingId: Number,
type: ItemType, // The item type being ranked
rankedId: Number, // The item being ranked
context: ArtistDetails | TagDetails,
value: Number, // The ranking (higher = better)
}
export function isRankingDetails(q: any): q is RankingDetails {
return 'rankingId' in q;
}
export interface SongDetails {
songId: Number,
title: String,
artists?: ArtistDetails[],
tags?: TagDetails[],
storeLinks?: String[],
rankings?: RankingDetails[],
}
export function isSongDetails(q: any): q is SongDetails {
return 'songId' in q;
}
// Query for items (POST).
export const QueryEndpoint = '/query';
export enum QueryElemOp {
And = "AND",
Or = "OR",
}
export enum QueryFilterOp {
Eq = "EQ",
Ne = "NE",
In = "IN",
NotIn = "NOTIN",
Like = "LIKE",
}
export enum QueryElemProperty {
songTitle = "songTitle",
songId = "songId",
artistName = "artistName",
albumName = "albumName",
}
export enum OrderBy {
Name = 0
}
export interface QueryElem {
prop?: QueryElemProperty,
propOperand?: any,
propOperator?: QueryFilterOp,
children?: QueryElem[]
childrenOperator?: QueryElemOp,
}
export interface Ordering {
orderBy: OrderBy,
ascending: boolean,
}
export interface Query extends QueryElem { }
export interface QueryRequest {
query: Query,
songOffset: number,
songLimit: number,
artistOffset: number,
artistLimit: number,
tagOffset: number,
tagLimit: number,
ordering: Ordering,
}
export interface QueryResponse {
songs: SongDetails[],
artists: ArtistDetails[],
tags: TagDetails[],
}
export function checkQueryElem(elem: any): boolean {
if (elem.childrenOperator && elem.children) {
elem.children.forEach((child: any) => {
if (!checkQueryElem(child)) {
return false;
}
});
}
return (elem.childrenOperator && elem.children) ||
(elem.prop && elem.propOperand && elem.propOperator) ||
Object.keys(elem).length == 0;
}
export function checkQueryRequest(req: any): boolean {
return 'query' in req
&& 'songOffset' in req
&& 'songLimit' in req
&& 'artistOffset' in req
&& 'artistLimit' in req
&& 'tagOffset' in req
&& 'tagLimit' in req
&& checkQueryElem(req.query);
}
// Get song details (GET).
export const SongDetailsEndpoint = '/song/:id';
export interface SongDetailsRequest { }
export interface SongDetailsResponse {
title: String,
storeLinks: String[],
artistIds: Number[],
albumIds: Number[],
tagIds: Number[],
}
export function checkSongDetailsRequest(req: any): boolean {
return true;
}
// Get artist details (GET).
export const ArtistDetailsEndpoint = '/artist/:id';
export interface ArtistDetailsRequest { }
export interface ArtistDetailsResponse {
name: String,
tagIds: Number[],
storeLinks: String[],
}
export function checkArtistDetailsRequest(req: any): boolean {
return true;
}
// Create a new song (POST).
export const CreateSongEndpoint = '/song';
export interface CreateSongRequest {
title: String;
artistIds?: Number[];
albumIds?: Number[];
tagIds?: Number[];
storeLinks?: String[];
}
export interface CreateSongResponse {
id: Number;
}
export function checkCreateSongRequest(req: any): boolean {
return "body" in req &&
"title" in req.body;
}
// Modify an existing song (PUT).
export const ModifySongEndpoint = '/song/:id';
export interface ModifySongRequest {
title?: String;
artistIds?: Number[];
albumIds?: Number[];
tagIds?: Number[];
storeLinks?: String[];
}
export interface ModifySongResponse { }
export function checkModifySongRequest(req: any): boolean {
return true;
}
// Create a new artist (POST).
export const CreateArtistEndpoint = '/artist';
export interface CreateArtistRequest {
name: String;
tagIds?: Number[];
storeLinks?: String[];
}
export interface CreateArtistResponse {
id: Number;
}
export function checkCreateArtistRequest(req: any): boolean {
return "body" in req &&
"name" in req.body;
}
// Modify an existing artist (PUT).
export const ModifyArtistEndpoint = '/artist/:id';
export interface ModifyArtistRequest {
name?: String,
tagIds?: Number[];
storeLinks?: String[],
}
export interface ModifyArtistResponse { }
export function checkModifyArtistRequest(req: any): boolean {
return true;
}
// Create a new tag (POST).
export const CreateTagEndpoint = '/tag';
export interface CreateTagRequest {
name: String;
parentId?: Number;
}
export interface CreateTagResponse {
id: Number;
}
export function checkCreateTagRequest(req: any): boolean {
return "body" in req &&
"name" in req.body;
}
// Modify an existing tag (PUT).
export const ModifyTagEndpoint = '/tag/:id';
export interface ModifyTagRequest {
name?: String,
parentId?: Number;
}
export interface ModifyTagResponse { }
export function checkModifyTagRequest(req: any): boolean {
return true;
}
// Get tag details (GET).
export const TagDetailsEndpoint = '/tag/:id';
export interface TagDetailsRequest { }
export interface TagDetailsResponse {
name: String,
parentId?: Number,
}
export function checkTagDetailsRequest(req: any): boolean {
return true;
}