Pushing errors back to frontend
Some checks failed
Music Collection CI Workflow / test (./backend) (push) Failing after 26s
Music Collection CI Workflow / test (./frontend) (push) Successful in 38s
Music Collection CI Workflow / build-and-push-images (./backend/Dockerfile, git.anatid.net/tabris/music-collection-backend, ./backend) (push) Has been skipped
Music Collection CI Workflow / build-and-push-images (./frontend/Dockerfile, git.anatid.net/tabris/music-collection-frontend, ./frontend) (push) Has been skipped
Music Collection CI Workflow / deploy (push) Has been skipped
Some checks failed
Music Collection CI Workflow / test (./backend) (push) Failing after 26s
Music Collection CI Workflow / test (./frontend) (push) Successful in 38s
Music Collection CI Workflow / build-and-push-images (./backend/Dockerfile, git.anatid.net/tabris/music-collection-backend, ./backend) (push) Has been skipped
Music Collection CI Workflow / build-and-push-images (./frontend/Dockerfile, git.anatid.net/tabris/music-collection-frontend, ./frontend) (push) Has been skipped
Music Collection CI Workflow / deploy (push) Has been skipped
This commit is contained in:
parent
040675bb5d
commit
2214fa32f5
@ -31,7 +31,9 @@ export class AlbumController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@UsePipes(new ValidationPipe({ transform: true }))
|
@UsePipes(new ValidationPipe({ transform: true }))
|
||||||
async create(@Body() createAlbumDto: CreateAlbumDto): Promise<Album | string | null> {
|
async create(
|
||||||
|
@Body() createAlbumDto: CreateAlbumDto,
|
||||||
|
): Promise<Album | string | null> {
|
||||||
return this.albumService.create(createAlbumDto);
|
return this.albumService.create(createAlbumDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,21 +13,24 @@ export class AlbumService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<Album[] | string | null> {
|
findAll(): Promise<Album[] | string | null> {
|
||||||
return this.albumRepository.find({
|
return this.albumRepository
|
||||||
|
.find({
|
||||||
order: {
|
order: {
|
||||||
artist: 'ASC',
|
artist: 'ASC',
|
||||||
title: 'ASC',
|
title: 'ASC',
|
||||||
},
|
},
|
||||||
}).then((albums) => {
|
})
|
||||||
|
.then((albums) => {
|
||||||
return albums;
|
return albums;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem getting the list of albums: ${error}`
|
return `There was a problem getting the list of albums: ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findOneById(id: number): Promise<Album | string | null> {
|
findOneById(id: number): Promise<Album | string | null> {
|
||||||
return this.albumRepository.findOne({
|
return this.albumRepository
|
||||||
|
.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: id,
|
id: id,
|
||||||
},
|
},
|
||||||
@ -39,13 +42,15 @@ export class AlbumService {
|
|||||||
trackNumber: 'ASC',
|
trackNumber: 'ASC',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).then((album) => {
|
})
|
||||||
|
.then((album) => {
|
||||||
return album;
|
return album;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem creating the Album identified by ID ${id}: ${error}`
|
return `There was a problem creating the Album identified by ID ${id}: ${error}`;
|
||||||
}).finally(() => {
|
})
|
||||||
return `There was a problem creating the Album identified by ID ${id}`
|
.finally(() => {
|
||||||
|
return `There was a problem creating the Album identified by ID ${id}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,12 +60,13 @@ export class AlbumService {
|
|||||||
artist: createAlbumDto.artist,
|
artist: createAlbumDto.artist,
|
||||||
genre: createAlbumDto.genre,
|
genre: createAlbumDto.genre,
|
||||||
});
|
});
|
||||||
return await this.albumRepository.save(album)
|
return await this.albumRepository
|
||||||
|
.save(album)
|
||||||
.then((savedAlbum) => {
|
.then((savedAlbum) => {
|
||||||
return savedAlbum;
|
return savedAlbum;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem creating the Album (${createAlbumDto.title} by ${createAlbumDto.artist} (${createAlbumDto.genre})): ${error}`
|
return `There was a problem creating the Album (${createAlbumDto.title} by ${createAlbumDto.artist} (${createAlbumDto.genre})): ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,12 +106,13 @@ export class AlbumService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: number): Promise<DeleteResult | string | null> {
|
async remove(id: number): Promise<DeleteResult | string | null> {
|
||||||
return await this.albumRepository.delete(id)
|
return await this.albumRepository
|
||||||
|
.delete(id)
|
||||||
.then((deleteResult) => {
|
.then((deleteResult) => {
|
||||||
return deleteResult;
|
return deleteResult;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem deleting the Album identified by ID ${id}: ${error}`
|
return `There was a problem deleting the Album identified by ID ${id}: ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateAlbumDto {
|
export class CreateAlbumDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateAlbumDto {
|
export class UpdateAlbumDto {
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
@ -13,7 +14,6 @@ export class UpdateAlbumDto {
|
|||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
genre: string;
|
genre: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { ValidationPipe } from '@nestjs/common';
|
import { UnprocessableEntityException, ValidationError, ValidationPipe } from '@nestjs/common';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
@ -13,16 +13,53 @@ async function bootstrap() {
|
|||||||
allowedHeaders:
|
allowedHeaders:
|
||||||
'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Observe',
|
'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Observe',
|
||||||
});
|
});
|
||||||
app.useGlobalPipes(new ValidationPipe({
|
app.useGlobalPipes(
|
||||||
|
new ValidationPipe({
|
||||||
transform: true,
|
transform: true,
|
||||||
exceptionFactory: (errors) => {
|
whitelist: true,
|
||||||
const result = errors.map((error) => ({
|
exceptionFactory: (validationErrors: ValidationError[] = []) => {
|
||||||
property: error.property,
|
const getPrettyClassValidatorErrors = (
|
||||||
message: error.constraints[Object.keys(error.constraints)[0]],
|
validationErrors: ValidationError[],
|
||||||
}));
|
parentProperty = '',
|
||||||
return new UnprocessableEntityException(result);
|
): Array<{ property: string; errors: string[] }> => {
|
||||||
|
const errors : any[] = [];
|
||||||
|
|
||||||
|
const getValidationErrorsRecursively = (
|
||||||
|
validationErrors: ValidationError[],
|
||||||
|
parentProperty = '',
|
||||||
|
) => {
|
||||||
|
for (const error of validationErrors) {
|
||||||
|
const propertyPath = parentProperty
|
||||||
|
? `${parentProperty}.${error.property}`
|
||||||
|
: error.property;
|
||||||
|
|
||||||
|
if (error.constraints) {
|
||||||
|
errors.push({
|
||||||
|
property: propertyPath,
|
||||||
|
errors: Object.values(error.constraints),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.children?.length) {
|
||||||
|
getValidationErrorsRecursively(error.children, propertyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getValidationErrorsRecursively(validationErrors, parentProperty);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
const errors = getPrettyClassValidatorErrors(validationErrors);
|
||||||
|
|
||||||
|
return new UnprocessableEntityException({
|
||||||
|
message: 'validation error',
|
||||||
|
errors: errors,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
await app.listen(process.env.PORT ?? 3000);
|
await app.listen(process.env.PORT ?? 3000);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
import { Entity, Column, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
|
||||||
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateSongDto {
|
export class CreateSongDto {
|
||||||
@Column({ unique: true })
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
duration: number;
|
duration: number;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
trackNumber: number;
|
trackNumber: number;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
albumId: number;
|
albumId: number;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
|
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateSongDto {
|
export class UpdateSongDto {
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
@Column({ unique: true })
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
duration: number;
|
duration: number;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
trackNumber: number;
|
trackNumber: number;
|
||||||
|
|
||||||
@Column()
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
albumId: number;
|
albumId: number;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,9 @@ export class SongController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@UsePipes(new ValidationPipe({ transform: true }))
|
@UsePipes(new ValidationPipe({ transform: true }))
|
||||||
async create(@Body() createSongDto: CreateSongDto): Promise<Song | string | null> {
|
async create(
|
||||||
|
@Body() createSongDto: CreateSongDto,
|
||||||
|
): Promise<Song | string | null> {
|
||||||
return this.songService.create(createSongDto);
|
return this.songService.create(createSongDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,24 +16,28 @@ export class SongService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<Song[] | string | null> {
|
findAll(): Promise<Song[] | string | null> {
|
||||||
return this.songRepository.find({
|
return this.songRepository
|
||||||
|
.find({
|
||||||
order: {
|
order: {
|
||||||
trackNumber: 'ASC',
|
trackNumber: 'ASC',
|
||||||
},
|
},
|
||||||
}).then((songs) => {
|
})
|
||||||
|
.then((songs) => {
|
||||||
return songs;
|
return songs;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem getting the list of songs: ${error}`
|
return `There was a problem getting the list of songs: ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findOneById(id: number): Promise<Song | string | null> {
|
findOneById(id: number): Promise<Song | string | null> {
|
||||||
return this.songRepository.findOneBy({ id: id }).then((albums) => {
|
return this.songRepository
|
||||||
|
.findOneBy({ id: id })
|
||||||
|
.then((albums) => {
|
||||||
return albums;
|
return albums;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem getting the song identified by ID ${id}: ${error}`
|
return `There was a problem getting the song identified by ID ${id}: ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,18 +51,23 @@ export class SongService {
|
|||||||
song.duration = createSongDto.duration;
|
song.duration = createSongDto.duration;
|
||||||
song.trackNumber = createSongDto.trackNumber;
|
song.trackNumber = createSongDto.trackNumber;
|
||||||
song.album = album;
|
song.album = album;
|
||||||
return this.songRepository.save(song).then((albums) => {
|
return this.songRepository
|
||||||
|
.save(song)
|
||||||
|
.then((albums) => {
|
||||||
return albums;
|
return albums;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem creating the song (${createSongDto.trackNumber} ${createSongDto.title} (${createSongDto.duration}s) on the Album ${album.title} by ${album.artist}): ${error}`
|
return `There was a problem creating the song (${createSongDto.trackNumber} ${createSongDto.title} (${createSongDto.duration}s) on the Album ${album.title} by ${album.artist}): ${error}`;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unable to find Album with ID ${createSongDto.albumId}`);
|
throw new Error(`Unable to find Album with ID ${createSongDto.albumId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: number, updateSongDto: UpdateSongDto): Promise<Song | string | null> {
|
async update(
|
||||||
|
id: number,
|
||||||
|
updateSongDto: UpdateSongDto,
|
||||||
|
): Promise<Song | string | null> {
|
||||||
if (id == updateSongDto.id) {
|
if (id == updateSongDto.id) {
|
||||||
const album = await this.albumRepository.findOneBy({
|
const album = await this.albumRepository.findOneBy({
|
||||||
id: updateSongDto.albumId,
|
id: updateSongDto.albumId,
|
||||||
@ -91,12 +100,13 @@ export class SongService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: number): Promise<DeleteResult | string | null> {
|
async remove(id: number): Promise<DeleteResult | string | null> {
|
||||||
return await this.songRepository.delete(id)
|
return await this.songRepository
|
||||||
|
.delete(id)
|
||||||
.then((deleteResult) => {
|
.then((deleteResult) => {
|
||||||
return deleteResult;
|
return deleteResult;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return `There was a problem deleting the Song identified by ID ${id}: ${error}`
|
return `There was a problem deleting the Song identified by ID ${id}: ${error}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user