From b3222768bbc68f3eb2f7d154291965834d883afe Mon Sep 17 00:00:00 2001 From: Keitaroh Kobayashi Date: Sat, 17 Apr 2021 16:21:42 +0900 Subject: [PATCH] Update NJA to v1.0.2, change error response type to include level detail Closes #128 --- src/lib/dynamodb_logs.ts | 2 +- src/lib/index.ts | 4 +-- src/public.test.ts | 57 +++++++++++++++++++++++----------------- src/public.ts | 49 +++++++++++++++++++--------------- yarn.lock | 6 ++--- 5 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/lib/dynamodb_logs.ts b/src/lib/dynamodb_logs.ts index 307288e..97fec52 100644 --- a/src/lib/dynamodb_logs.ts +++ b/src/lib/dynamodb_logs.ts @@ -1,7 +1,7 @@ import { DB } from "./dynamodb" import { ulid } from "ulid" -export const createLog = async (identifier: string, metadata: { [key: string]: string }, now: Date = new Date()): Promise => { +export const createLog = async (identifier: string, metadata: { [key: string]: any }, now: Date = new Date()): Promise => { const nowStr = now.toISOString() const datePart = nowStr.slice(0, 10) const PK = `LOG#${identifier}#${datePart}` diff --git a/src/lib/index.ts b/src/lib/index.ts index a1cdca4..5d3b941 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -115,8 +115,8 @@ export const yokobo2zenchoonSymbol = (str: string) => { return str.replace(/[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/gi,'ー') // 長音記号に変換 } -export const normalizeBuilding = (building: string | undefined ): string | undefined => { - if(undefined === building) { +export const normalizeBuilding = (building?: string ): string | undefined => { + if (typeof building === 'undefined' || building.trim() === "") { return undefined } return yokobo2zenchoonSymbol(zen2hanAscii(building.trim())) diff --git a/src/public.test.ts b/src/public.test.ts index 9b43122..b8621d7 100644 --- a/src/public.test.ts +++ b/src/public.test.ts @@ -268,35 +268,44 @@ test('should get estate ID with details if authenticated with 和歌山県東牟 ]) }) -test('should return 400 with insufficient address.', async () => { - const addresses = [ - '和歌山県東牟婁郡' - ] +describe("normalization error cases", () => { + test('should return 400 with insufficient address.', async () => { + const addresses = [ + ['和歌山県東牟婁郡', 'city_not_recognized'], + ['和歌山県aoeu', 'city_not_recognized'], + ['和歌県', 'prefecture_not_recognized'], + ['おはよう', 'prefecture_not_recognized'], + ] + + for (const addressData of addresses) { + const [ address, expectedErrorCodeDetail ] = addressData + const event = { + isDemoMode: true, + queryStringParameters: { + q: address + } + } + + // @ts-ignore + const resp = await handler(event) as APIGatewayProxyResult + const body = JSON.parse(resp.body) + expect(resp.statusCode).toEqual(400) + expect(body.error_code).toBe("normalization_failed") + expect(body.error_code_detail).toBe(expectedErrorCodeDetail) + } + }) - for (const address of addresses) { + test('should return 400 with empty address', async () => { const event = { isDemoMode: true, - queryStringParameters: { - q: address - } + queryStringParameters: null } - // @ts-ignore - const lambdaResult = await handler(event) as APIGatewayProxyResult - expect(lambdaResult.statusCode).toEqual(400) - } -}) - -test('should return 400 with empty address', async () => { - const event = { - isDemoMode: true, - queryStringParameters: null - } - // @ts-ignore - const { statusCode, body } = await handler(event) - const { message } = JSON.parse(body) - expect(statusCode).toEqual(400) - expect(message).toEqual('Missing querystring parameter `q`.') + const { statusCode, body } = await handler(event) + const { message } = JSON.parse(body) + expect(statusCode).toEqual(400) + expect(message).toEqual('Missing querystring parameter `q`.') + }) }) test('should return 403 if not authenticated.', async () => { diff --git a/src/public.ts b/src/public.ts index 7f6f618..bc25d67 100644 --- a/src/public.ts +++ b/src/public.ts @@ -8,6 +8,11 @@ import { Handler, APIGatewayProxyResult } from 'aws-lambda' import { authenticateEvent, extractApiKey } from './lib/authentication' import { createLog } from './lib/dynamodb_logs' +const NORMALIZATION_ERROR_CODE_DETAILS = [ + "prefecture_not_recognized", + "city_not_recognized", +] + export const _handler: Handler = async (event) => { const address = event.queryStringParameters?.q const building = event.queryStringParameters?.building @@ -33,27 +38,23 @@ export const _handler: Handler = asyn }) // Internal normalization - let prenormalizedAddress: NormalizeResult - try { - prenormalizedAddress = await normalize(address) - - await createLog(`normLogsNJA`, { - input: address, - normalized: JSON.stringify(prenormalizedAddress), - }) + const prenormalizedAddress = await normalize(address) + await createLog(`normLogsNJA`, { + input: address, + level: prenormalizedAddress.level, + normalized: JSON.stringify(prenormalizedAddress), + }) - } catch (error) { - Sentry.captureException(error) - console.error({ error }) - if ('address' in error) { - // this is a normalize-japanese-addressses error - await createLog(`normFailNJA`, { - input: address, - errorMsg: error.message, - }) - } - return errorResponse(400, `address ${address} can not be normalized.`) + if (prenormalizedAddress.level < 2) { + const error_code_detail = NORMALIZATION_ERROR_CODE_DETAILS[prenormalizedAddress.level] + return json({ + error: true, + error_code: `normalization_failed`, + error_code_detail, + address, + }, 400) } + const normalizedBuilding = normalizeBuilding(building) if (!prenormalizedAddress.town || prenormalizedAddress.town === '') { @@ -65,6 +66,7 @@ export const _handler: Handler = asyn const normalizedAddressNJA = `${prenormalizedAddress.pref}${prenormalizedAddress.city}${prenormalizedAddress.town}${prenormalizedAddress.addr}` const ipcResult = await incrementPGeocode(normalizedAddressNJA) if (!ipcResult) { + Sentry.captureException(new Error(`IPC result null`)) return errorResponse(500, 'Internal server error') } @@ -81,7 +83,12 @@ export const _handler: Handler = asyn prenormalized: normalizedAddressNJA, ipcResult: JSON.stringify(ipcResult), }) - return errorResponse(404, "The address '%s' is not verified.", address) + + return json({ + error: true, + error_code: `address_not_verified`, + address, + }, 404) } const [lng, lat] = feature.geometry.coordinates as [number, number] @@ -137,7 +144,7 @@ export const _handler: Handler = asyn return errorResponse(500, 'Internal Server Error.') } - const ID = estateId!.estateId + const ID = estateId.estateId let body: any if (authenticationResult.plan === "paid" || event.isDemoMode) { diff --git a/yarn.lock b/yarn.lock index fdfe66d..2677607 100644 --- a/yarn.lock +++ b/yarn.lock @@ -310,9 +310,9 @@ integrity sha512-LO1f4Bw/UF5OIWAavX9CyclxYCsHPDe6h/CWL/1RInc3QLMkEGicZp++qyfjodDsPKMCs84GReJapQnPWl3ZUQ== "@geolonia/normalize-japanese-addresses@*": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-0.1.9.tgz#59aa9597dafcb4170c31b947bfac7833b1f8e24f" - integrity sha512-/D+D5GjrjmR34N1S5p/sbRsortR0fGYncdWLJMUADvEZUzo4mP6fSwbfEDXS7Rz9W9+bFbRpKC1piRBY+iehwg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-1.0.2.tgz#e1bab3443265b1288e9798aa6e9de1509222431b" + integrity sha512-KfewiWewUhrAkzrvQeqFH+AXonCqDRjGlR18qiXmA78gtq0GzyeXIZHCowMY3iwd1wRaEZ6PgZXA+FLNvUCCJQ== dependencies: "@geolonia/japanese-numeral" "^0.1.11" node-fetch "^2.6.1"