/** * Japan Post Address Service * * Address lookup service using Japan Post API. * Transforms raw API responses to domain types using domain mappers. */ import { Injectable, Inject, BadRequestException, ServiceUnavailableException, } from "@nestjs/common"; import { Logger } from "nestjs-pino"; import { extractErrorMessage } from "@bff/core/utils/error.util.js"; import { JapanPostConnectionService } from "./japanpost-connection.service.js"; import { JapanPost } from "@customer-portal/domain/address/providers"; import type { AddressLookupResult } from "@customer-portal/domain/address"; @Injectable() export class JapanPostAddressService { constructor( private readonly connection: JapanPostConnectionService, @Inject(Logger) private readonly logger: Logger ) {} /** * Lookup address by ZIP code * * @param zipCode - ZIP code (with or without hyphen, e.g., "100-0001" or "1000001") * @returns Domain AddressLookupResult with Japanese and romanized address data * @throws BadRequestException if ZIP code format is invalid * @throws ServiceUnavailableException if Japan Post API is unavailable */ async lookupByZipCode(zipCode: string): Promise { // Normalize ZIP code (remove hyphen) const normalizedZip = zipCode.replace(/-/g, ""); // Validate format if (!/^\d{7}$/.test(normalizedZip)) { throw new BadRequestException("ZIP code must be 7 digits (e.g., 100-0001)"); } // Check if service is configured if (!this.connection.isConfigured()) { this.logger.error("Japan Post API not configured"); throw new ServiceUnavailableException("Address lookup service is not available"); } try { const rawResponse = await this.connection.searchByZipCode(normalizedZip); // Use domain mapper for transformation (single transformation point) const result = JapanPost.transformJapanPostSearchResponse(rawResponse); this.logger.log("Japan Post address lookup completed", { zipCode: normalizedZip, found: result.count > 0, count: result.count, }); return result; } catch (error) { // Re-throw known exceptions if (error instanceof BadRequestException || error instanceof ServiceUnavailableException) { throw error; } this.logger.error("Japan Post address lookup failed", { zipCode: normalizedZip, error: extractErrorMessage(error), }); throw new ServiceUnavailableException("Failed to lookup address. Please try again."); } } /** * Check if the Japan Post service is available */ isAvailable(): boolean { return this.connection.isConfigured(); } }