Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 2x 2x 2x 2x 2x 2x 5x 5x 14x 14x 1x 1x 13x 13x 13x 3x 3x 10x 10x 10x 1x 1x 9x 9x 9x 9x 13x 9x 9x | import { ClientInterface } from '@Application/Shared/Pokemon/ClientInterface';
import { Pokemon } from '@Domain/ValueObjects/Pokemon';
import { Result } from '@Domain/Types/Result';
import { HttpError } from '@Domain/Errors/HttpError';
import { PokemonSpecies } from '@Infrastructure/ExternalService/Pokemon/types';
import { ValidationError } from '@Domain/Errors/ValidationError';
import { LoggerInterface } from '@Application/Shared/Monitoring/LoggerInterface';
import config from '@Infrastructure/Environments/config';
/**
* HTTP client for communicating with the Pokemon API
*/
export class HttpClient implements ClientInterface {
private readonly baseUrl = config.pokemonClient.baseUrl;
constructor(private readonly logger: LoggerInterface) { }
/**
* Retrieves Pokemon data from the external API
* @param name The name of the Pokemon to retrieve
* @returns A promise resolving to a Result containing either the Pokemon data or an Error
*/
async getPokemon(name: string): Promise<Result<Error, Pokemon>> {
this.logger.info(`Fetching pokemon`, { name });
if (!name) {
this.logger.error(`Name is required`, {
name,
});
return {
success: false,
error: new ValidationError('Name is required'),
};
}
let response: Response;
try {
response = await fetch(`${this.baseUrl}/${name.toLowerCase()}`);
} catch (error) {
this.logger.error(`Failed to fetch pokemon`, {
name,
body: error,
});
return {
success: false,
error: new HttpError(500, `Failed to fetch pokemon '${name}'`),
};
}
if (!response.ok) {
this.logger.error(`Failed to fetch pokemon`, {
name,
status: response.status,
body: await response.text(),
});
return {
success: false,
error: new HttpError(response.status, `Failed to fetch pokemon '${name}'`),
};
}
const data = await response.json();
const result = PokemonSpecies.safeParse(data);
if (!result.success) {
this.logger.error(`Failed to parse pokemon`, {
name,
body: data,
error: result.error.message,
});
return {
success: false,
error: new ValidationError(result.error.message),
};
} else {
this.logger.info(`Pokemon fetched successfully`, { name });
this.logger.debug(`Pokemon fetched successfully: body`, { name, body: data });
return {
success: true,
data: this.mapToPokemon(result.data),
};
}
}
/**
* Maps the API response to the Pokemon domain object
* @param data The raw data from the API
* @returns A Pokemon domain object
*/
private mapToPokemon(data: PokemonSpecies): Pokemon {
const descriptionEntry = data.flavor_text_entries.find(
(entry) => entry.language.name === 'en'
);
const description = descriptionEntry
? descriptionEntry.flavor_text.replace(/[\n\f\r]/g, ' ')
: '';
return new Pokemon(
data.name,
description,
data.habitat ? data.habitat.name : 'unknown',
data.is_legendary
);
}
}
|