Skip to content

Commit 1b8fb73

Browse files
chore: correction step 1
1 parent 1d7c9b0 commit 1b8fb73

8 files changed

Lines changed: 5346 additions & 42 deletions

File tree

src/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Module } from '@nestjs/common';
22
import { AppController } from './app.controller';
33
import { AppService } from './app.service';
4+
import { PokemonModule } from './pokemon/pokemon.module';
45

56
@Module({
6-
imports: [],
7+
imports: [PokemonModule],
78
controllers: [AppController],
89
providers: [AppService],
910
})

src/pokemon/dtos/get-pokemon-by-name.query.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { ApiProperty } from '@nestjs/swagger';
22
import { IsString } from 'class-validator';
33

44
export class GetPokemonByNameQuery {
5-
@ApiProperty({ type: 'string' })
5+
@ApiProperty({
6+
type: 'string',
7+
description:
8+
'pokemon name, must be exact and must be the name of a first-generation pokemon',
9+
})
610
@IsString()
711
name: string;
812
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Type } from 'class-transformer';
3+
import { IsArray, IsNumber, IsString } from 'class-validator';
4+
5+
class PokemonSpeciesResponse {
6+
@ApiProperty({
7+
type: 'string',
8+
description: 'species name',
9+
})
10+
@IsString()
11+
name: string;
12+
13+
@ApiProperty({
14+
type: 'string',
15+
description: 'species URL',
16+
})
17+
@IsString()
18+
url: string;
19+
}
20+
21+
export class GetPokemonByNameResponse {
22+
@ApiProperty({
23+
type: 'string',
24+
description: 'pokemon name',
25+
})
26+
@IsString()
27+
name: string;
28+
29+
@ApiProperty({
30+
type: 'number',
31+
description: 'pokemon ID (from 1 to 151)',
32+
})
33+
@IsNumber()
34+
id: number;
35+
36+
@ApiProperty({
37+
type: 'number',
38+
description: 'height',
39+
})
40+
@IsNumber()
41+
height: number;
42+
43+
@ApiProperty({
44+
type: 'number',
45+
description: 'weight',
46+
})
47+
@IsNumber()
48+
weight: number;
49+
50+
@ApiProperty({
51+
type: [String],
52+
description: 'pokemon ID (from 1 to 151)',
53+
})
54+
@IsArray()
55+
@IsString({ each: true })
56+
types: string[];
57+
58+
@ApiProperty({
59+
type: () => PokemonSpeciesResponse,
60+
description: 'pokemon species',
61+
})
62+
@Type(() => PokemonSpeciesResponse)
63+
species: PokemonSpeciesResponse;
64+
}

src/pokemon/pokemon.controller.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
export var pokemonApiUrl = 'http://pokeapi.co/api/v2';
2-
31
import {
2+
BadRequestException,
43
Controller,
54
Get,
65
HttpException,
7-
Inject,
6+
InternalServerErrorException,
87
NotFoundException,
9-
Param,
10-
Post,
118
Query,
129
UseInterceptors,
1310
} from '@nestjs/common';
@@ -16,51 +13,62 @@ import { GetPokemonByNameQuery } from './dtos/get-pokemon-by-name.query';
1613
import { Pokemon } from './types/pokemon';
1714
import { AuthInterceptor } from '../auth/auth.interceptor';
1815
import {
16+
ApiBadRequestResponse,
1917
ApiInternalServerErrorResponse,
18+
ApiNotFoundResponse,
2019
ApiQuery,
2120
ApiResponse,
2221
ApiTags,
2322
} from '@nestjs/swagger';
23+
import { PokemonNotFoundError } from './types/error';
24+
import { GetPokemonByNameResponse } from './dtos/get-pokemon-by-name.response';
2425

2526
@Controller('pokemon')
2627
@ApiTags('pokemon')
2728
@UseInterceptors(AuthInterceptor)
2829
export class PokemonController {
2930
constructor(private pokemonService: PokemonService) {}
3031

31-
@Post('pokemon')
32+
@Get('pokemon')
3233
@ApiQuery({
3334
type: GetPokemonByNameQuery,
3435
description: 'Lookup string for pokemons (match against pokemon name)',
3536
})
3637
@ApiResponse({
3738
status: 200,
38-
description: 'Returns pokemons whose name matches a string query param',
39+
type: GetPokemonByNameResponse,
40+
description:
41+
'Returns a pokemon whose name exactly matches the string query param',
42+
})
43+
@ApiBadRequestResponse({
44+
description: 'Returned if query param "name" is empty',
45+
})
46+
@ApiNotFoundResponse({
47+
description:
48+
'Returned if no first-generation pokemon was found for this name',
3949
})
4050
@ApiInternalServerErrorResponse({
41-
description: 'This will never happen, trust me',
51+
description: 'Returned if any other error is encountered',
4252
})
4353
async GetPokemonByNameController(
44-
@Query() name: any,
45-
): Promise<Pokemon | null> {
46-
if (name === null) return;
47-
48-
name == null
49-
? name.trim() != ''
50-
? ((name = name),
51-
(pokemonApiUrl = pokemonApiUrl + '/'),
52-
(pokemonApiUrl = pokemonApiUrl + name))
53-
: ((pokemonApiUrl = pokemonApiUrl + '"?offset=20"'),
54-
(pokemonApiUrl = pokemonApiUrl + '&limit=20'))
55-
: ((pokemonApiUrl = pokemonApiUrl + '"?offset=20"'),
56-
(pokemonApiUrl = pokemonApiUrl + '&limit=20'));
57-
58-
console.log('Printing name for debug : ', name);
59-
60-
const myPokemon = await this.pokemonService.findPokemonByNameOrFail(name);
54+
@Query('name') name: string,
55+
): Promise<Pokemon> {
56+
try {
57+
if (name === undefined || name.length === 0) {
58+
throw new BadRequestException('Pokemon name cannot be empty');
59+
}
6160

62-
console.log('Printing name for debug : ', myPokemon);
61+
const myPokemon = await this.pokemonService.findPokemonByNameOrFail(name);
6362

64-
return myPokemon;
63+
return myPokemon;
64+
} catch (error) {
65+
if (error instanceof PokemonNotFoundError) {
66+
throw new NotFoundException(error);
67+
} else if (error instanceof HttpException) {
68+
throw error;
69+
} else {
70+
throw new InternalServerErrorException(error);
71+
}
72+
}
6573
}
6674
}

src/pokemon/pokemon.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { PokemonService } from './pokemon.service';
44

55
@Module({
66
controllers: [PokemonController],
7-
providers: [PokemonService]
7+
providers: [PokemonService],
88
})
99
export class PokemonModule {}

src/pokemon/pokemon.service.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { Injectable } from '@nestjs/common';
2-
import got, { Got } from 'got';
2+
import got from 'got';
33
import { Pokemon } from './types/pokemon';
4-
import { pokemonApiUrl } from './pokemon.controller';
4+
55
import { PokemonSpecies } from './types/species';
6+
import { PokemonNotFoundError, UnexpectedError } from './types/error';
67

8+
const POKEMON_API_URL = 'http://pokeapi.co/api/v2';
9+
const FIRST_GENERATION_POKEMON_LAST_ID = 151;
710
@Injectable()
811
export class PokemonService {
9-
private httpClient: Got;
10-
constructor() {
11-
this.httpClient = got.extend({
12-
prefixUrl: pokemonApiUrl,
13-
responseType: 'json',
14-
throwHttpErrors: false,
15-
});
16-
}
12+
private readonly httpClient = got.extend({
13+
prefixUrl: POKEMON_API_URL,
14+
responseType: 'json',
15+
throwHttpErrors: false,
16+
});
1717

1818
async findPokemonByNameOrFail(pokemonName: string): Promise<Pokemon> {
1919
type GetPokemonResponse = {
@@ -30,7 +30,15 @@ export class PokemonService {
3030
.then((response) => response.body as unknown as GetPokemonResponse)
3131
.then((body) => {
3232
if (!body.id) {
33-
return null;
33+
throw new PokemonNotFoundError(
34+
`No pokemon found for name '${pokemonName}'`,
35+
);
36+
}
37+
38+
if (body.id > FIRST_GENERATION_POKEMON_LAST_ID) {
39+
throw new PokemonNotFoundError(
40+
`Pokemon '${pokemonName}' is not first-generation: ID ${body.id} > ${FIRST_GENERATION_POKEMON_LAST_ID}`,
41+
);
3442
}
3543

3644
const types = body.types
@@ -50,7 +58,11 @@ export class PokemonService {
5058
};
5159
})
5260
.catch((error) => {
53-
throw error;
61+
if (error instanceof PokemonNotFoundError) {
62+
throw error;
63+
}
64+
65+
throw new UnexpectedError(error);
5466
});
5567
}
5668
}

src/pokemon/types/error.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export class PokemonNotFoundError extends Error {}
2+
3+
export class UnexpectedError extends Error {}

0 commit comments

Comments
 (0)