Assist_Design/apps/bff/src/modules/address/address.controller.ts

101 lines
2.8 KiB
TypeScript

/**
* Address Controller
*
* HTTP endpoints for address lookup and management.
*/
import {
Controller,
Get,
Param,
Req,
UseGuards,
UseInterceptors,
ClassSerializerInterceptor,
} from "@nestjs/common";
import type { Request } from "express";
import { createZodDto } from "nestjs-zod";
import { Public } from "@bff/modules/auth/decorators/public.decorator.js";
import { RateLimitGuard, RateLimit } from "@bff/core/rate-limiting/index.js";
import { extractClientIp } from "@bff/core/http/request-context.util.js";
import { JapanPostFacade } from "@bff/integrations/japanpost/index.js";
import {
addressLookupResultSchema,
zipCodeLookupRequestSchema,
} from "@customer-portal/domain/address";
// ============================================================================
// DTOs
// ============================================================================
/**
* ZIP code parameter DTO
* Validates ZIP code format (with or without hyphen)
*/
class ZipCodeParamDto extends createZodDto(zipCodeLookupRequestSchema) {}
/**
* Address lookup result DTO
*/
class AddressLookupResultDto extends createZodDto(addressLookupResultSchema) {}
// ============================================================================
// Controller
// ============================================================================
@Controller("address")
@UseInterceptors(ClassSerializerInterceptor)
export class AddressController {
constructor(private readonly japanPost: JapanPostFacade) {}
/**
* Lookup address by ZIP code
*
* @route GET /api/address/lookup/zip/:zipCode
* @param zipCode - Japanese ZIP code (e.g., "100-0001" or "1000001")
* @returns Address lookup result with Japanese and romanized address data
*
* @example
* GET /api/address/lookup/zip/100-0001
* Response:
* {
* "zipCode": "1000001",
* "addresses": [
* {
* "zipCode": "1000001",
* "prefecture": "東京都",
* "city": "千代田区",
* "town": "千代田",
* "prefectureRoma": "Tokyo",
* "cityRoma": "Chiyoda-ku",
* "townRoma": "Chiyoda"
* }
* ],
* "count": 1
* }
*/
@Public()
@Get("lookup/zip/:zipCode")
@UseGuards(RateLimitGuard)
@RateLimit({ limit: 30, ttl: 60 }) // 30 requests per minute
async lookupByZipCode(
@Param() params: ZipCodeParamDto,
@Req() req: Request
): Promise<AddressLookupResultDto> {
const clientIp = extractClientIp(req);
return this.japanPost.lookupByZipCode(params.zipCode, clientIp);
}
/**
* Check if address lookup service is available
*
* @route GET /api/address/status
* @returns Service availability status
*/
@Public()
@Get("status")
getStatus(): { available: boolean } {
return { available: this.japanPost.isAvailable() };
}
}