@crvouga/ mockingbird-service-google-地图
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
模拟 谷歌地图平台 显示我们的会员应用地址: 位置
自动完成, Place 细节并从文本中查找位置( JSON 网络服务), Geocoding API,
(单位:千美元) 地图 JavaScript API shim (单位:千美元)/maps/api/js?libraries=places) 揭露
google.maps.places.* 财务报告和审定财务报表 google.maps.Geocoder 在相同数据上 地址
验证 API (单位:千美元)POST /v1:validateAddress,并附有USPS CASS/DPV数据),用于服务器侧船到
检查。 答案来自一个机构
匹配我们的 QA 设置, 因此地址步骤等待 5 s 的 Google 预测( 然后)
回到手动输入)立即解决,决定性地解决.
- 行动范围: 支助
- Google 没有针对这些端点发布 OpenAPI 文档 :
openapi.yaml手写 从Google的文档形状 和我们消费者读的字段。 以下地址验证 页:1 REST 参考文献 财务报告和审定财务报表ValidationResult。 。 。 .
安装
npm install -D @crvouga/mockingbird-service-google-maps
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-google-maps serve, (中文(简体) ), createServer 从 ./server (节点),或 createRuntime
与任何获取服务器.
使用量
应用程序硬码 https://maps.googleapis.com (接缝) G-Y1级: 用于
M/lib/ui/address-autocomplete/address-autocomplete-native-rest.tsx, (中文(简体) ),
M/features/bloodwork/shared/lab-finder/use-geocoded-address.ts 财务报告和审定财务报表
M/lib/ui/google-maps/load-google-maps-script.ts) (中文(简体) ). 在它降落之前 将宿主重写成模拟者
在堆栈的网盘中( t)stack-web-dist.ts),至于后霍格语. PLACES_KEY 可以是任何非空的
字符串,除非限制键.
npx mockingbird-google-maps serve --port 8814 --api-key "$PLACES_KEY"
import { Client, PlaceAutocompleteType } from "@googlemaps/google-maps-services-js"
import { createRuntime } from "@crvouga/mockingbird-service-google-maps"
// The Maps client your application already uses. Only its HTTP layer changes: axios's
// fetch adapter reaches the emulator in this process instead of maps.googleapis.com.
const emulator = createRuntime()
const maps = new Client({
config: {
adapter: "fetch",
env: { fetch: (url: string | URL | Request, init?: RequestInit) => emulator.fetch(new Request(url, init)) },
},
})
const { data } = await maps.placeAutocomplete({
params: { input: "1625 N Central", types: PlaceAutocompleteType.address, components: ["country:us"], key: "k" },
})
const details = await maps.placeDetails({
params: { place_id: data.predictions[0]?.place_id ?? "", fields: ["address_component"], key: "k" },
})
// details.data.result.address_components → 1625 / N Central Ave / Phoenix / AZ / 85004
// Test control: make the next two autocomplete calls fail, as QA's manual-entry fallback expects.
emulator.applyPreset("autocomplete_over_query_limit", "default", { count: 2 })
地址验证
谷歌服务它来自不同的主机, https://addressvalidation.googleapis.com; 路径
不相撞,所以一个仿真器服务于两者。 指向服务器端客户端的地址验证基址
在模拟器上(或 <emulator>/__admin/ns/<namespace>),键为 ?key= (或 X-Goog-Api-Key) (中文(简体) ).
import { AddressValidationClient } from "@googlemaps/addressvalidation"
import { createServer } from "@crvouga/mockingbird-service-google-maps/server"
const server = await createServer()
const { hostname, port } = new URL(server.url)
// The application's client, in REST mode. Only the endpoint changes.
const client = new AddressValidationClient({
fallback: true,
protocol: "http",
apiEndpoint: hostname,
port: Number(port),
apiKey: "k",
})
const [{ result }] = await client.validateAddress({
address: {
regionCode: "US",
addressLines: ["1625 N Central Ave"],
locality: "Phoenix",
administrativeArea: "AZ",
postalCode: "85004",
},
enableUspsCass: true,
})
// result.verdict → PREMISE / addressComplete; result.uspsData.dpvConfirmation → "Y"
// Test control: force the USPS "not deliverable" answer on the next call.
server.runtime.applyPreset("address_validation_dpv_n", "default", { count: 1 })
await client.close()
await server.close()
网上装入 <emulator>/maps/api/js?key=…&libraries=places 和Google的应用程序一样
脚本;shim调回模拟器的 REST 端点在同一来源和命名空间上.
路线
每个网络服务的答案是 HTTP 200 (韩语) 与谷歌的 status (单位:千美元)OK, (中文(简体) ), ZERO_RESULTS, (中文(简体) ),
INVALID_REQUEST, (中文(简体) ), NOT_FOUND, (中文(简体) ), REQUEST_DENIED, (中文(简体) ), OVER_QUERY_LIMIT, (中文(简体) ), UNKNOWN_ERROR并且,为了
错误,谷歌 error_messageB. 答复 access-control-allow-origin: * 所以,嘘
从浏览器工作.
| 路线 | 行为 |
|---|---|
GET /maps/api/place/autocomplete/json | input (必须,其他 INVALID_REQUEST, (中文(简体) ), types, (中文(简体) ), components=country:us, (中文(简体) ), sessiontoken。 。 。 . predictions[] 与 description, (中文(简体) ), place_id, (中文(简体) ), reference, (中文(简体) ), structured_formatting{main_text, main_text_matched_substrings, secondary_text}, (中文(简体) ), terms, (中文(简体) ), types, (中文(简体) ), matched_substrings; 最多为 5. 以符号前缀相匹配(街道、城市、州、ZIP); "<number> <street> <corpus city>[ <ST>][ <ZIP>]" 实值 已合成 在那一行的城市/州/ZIP(QA模糊搜索). 没什么 ZERO_RESULTS; 一个非 美国 components → ZERO_RESULTS。 。 。 . |
GET /maps/api/place/details/json | place_id (必须), fields (荣誉: address_component 仅返回 address_components页:1 INVALID_REQUEST, (中文(简体) ), sessiontoken。 。 。 . result 与 address_components (单位:千美元)street_number, (中文(简体) ), route, (中文(简体) ), locality, (中文(简体) ), administrative_area_level_2, (中文(简体) ), administrative_area_level_1 长/短, country, (中文(简体) ), postal_code, (中文(简体) ), formatted_address, (中文(简体) ), geometry{location, viewport}, (中文(简体) ), place_id, (中文(简体) ), types, (中文(简体) ), name, (中文(简体) ), url, (中文(简体) ), vicinity。未知编号 NOT_FOUND。 。 。 . |
GET /maps/api/geocode/json | address, (中文(简体) ), place_id 或者说 components=postal_code:… (无) INVALID_REQUEST) (中文(简体) ). results[0] 与 address_components, (中文(简体) ), formatted_address, (中文(简体) ), geometry{location, location_type, viewport}, (中文(简体) ), place_id, (中文(简体) ), types完整地址:"line1, city, ST zip"解决其行或合成地址; 赤裸的ZIP或 "City, ST" 至 ZIP 中间体; 没有可移动城市的街道是 ZERO_RESULTS。 。 。 . |
GET /maps/api/place/findplacefromtext/json | input + 键 inputtype=textquery (次数) INVALID_REQUEST, (中文(简体) ), fields (默认 : place_id 仅作为谷歌). 先是地理编码,然后是比较松散的自动完成匹配, 所以它找到我们的地理编码回落需要什么. |
POST /v1:validateAddress | 地址验证(见下文)。 谷歌云 API:错误为 HTTP 4xx/5xx 与 {"error": {code, message, status}},而不是200与 status。 。 。 . |
GET /maps/api/js | 嘘text/javascript: google.maps.places.AutocompleteService#getPlacePredictions, (中文(简体) ), PlacesService#getDetails 编号 : #findPlaceFromQuery, (中文(简体) ), AutocompleteSessionToken, (中文(简体) ), PlacesServiceStatus, (中文(简体) ), google.maps.Geocoder#geocode, (中文(简体) ), GeocoderStatus, (中文(简体) ), LatLng (单位:千美元)lat()编号 :lng(), (中文(简体) ), LatLngBounds, (中文(简体) ), importLibrary。回电和承诺(以 MapsRequestError 在不给回话时错误。 电话 window[callback] 页:1 &callback=,以及 window.gm_authFailure() 当密钥被拒绝时. |
地址验证判决
正如Google发送的 false 删除布尔和空列表
(无) unconfirmedComponentTypes: []) (中文(简体) ). result 携带 verdict (单位:千美元)inputGranularity, (中文(简体) ),
validationGranularity, (中文(简体) ), geocodeGranularity, (中文(简体) ), addressComplete, (中文(简体) ), has*Components, (中文(简体) ),
possibleNextAction, (中文(简体) ), address (单位:千美元)formattedAddress, (中文(简体) ), postalAddress, (中文(简体) ), addressComponents 与
confirmationLevel 编号 : inferred 编号 : replaced, (中文(简体) ), missingComponentTypes, (中文(简体) ),
unconfirmedComponentTypes, (中文(简体) ), geocode (单位:千美元)location, (中文(简体) ), placeId, (中文(简体) ), placeTypes和,美国
地址:, uspsData (单位:千美元)standardizedAddress, (中文(简体) ), dpvConfirmation, (中文(简体) ), dpvFootnote, (中文(简体) ),
postOfficeCity编号 :State, (中文(简体) ), errorMessage, (中文(简体) ), cassProcessed 何时 enableUspsCass) (中文(简体) ). 每一个答案
有一个 responseId,发送一个组件地址(1行+可选单元2行), locality, (中文(简体) ),
administrativeArea, (中文(简体) ), postalCode或所有的东西 addressLines。 。 。 .
| 投入 | 判决 |
|---|---|
实体行( A)1625 N Central Ave, Phoenix AZ 8504; 拼出单词(North, (中文(简体) ), Avenue匹配( r) | PREMISE完整地说, ACCEPT,DPV Y· ; postalAddress 以确定性ZIP+4(85004-NNNN(中文(简体) ) |
<number> <street> 在一个城市里 | 合成, 至于自动完成 : PREMISE, (中文(简体) ), ACCEPT,DPV Y,街道USPS缩略语(Maple Street → Maple St(中文(简体) ) |
单发点行上的单元(… Building A, (中文(简体) ), Apt 4(中文(简体) ) | PREMISE完整地说, CONFIRM, (中文(简体) ), subpremise 未证实,DPV Y |
无房号(N Central Ave) 在一个实体城市 | ROUTE, (中文(简体) ), FIX, (中文(简体) ), missingComponentTypes: ["street_number"],无 DPV 代码 |
| 一个城市/ZIP 保护令没有 | OTHER, (中文(简体) ), FIX,不可置放的组件未经证实,DPV N |
| 对城市不利的ZIP(或对ZIP不利的城市) | 已替换 : hasReplacedComponents, (中文(简体) ), CONFIRM,在 postalAddress |
一行为 validation.multiUnit | 无单位 : CONFIRM_ADD_SUBPREMISES, (中文(简体) ), missingComponentTypes: ["subpremise"],DPV D中的单位 validation.units (或任何,何时) units 缺席 : SUB_PREMISE, (中文(简体) ), ACCEPT, (中文(简体) ), Y。另一个单位: PREMISE, (中文(简体) ), CONFIRM, (中文(简体) ), subpremise 未证实,DPV S |
一行为 validation.uspsErrorMessage | uspsData: {errorMessage} 没有 DPV 代码 |
没有 address空无 addressLines,一个未知字段,非JSON,超过280个字符,或者 enableUspsCass 外部 US编号 :PR | 400个 INVALID_ARGUMENT |
| 无密钥 | 403 (韩语) PERMISSION_DENIED "请求缺少有效的API密钥" |
外部键 settings.keys | 400个 INVALID_ARGUMENT "API密钥无效. 请通过有效的 API 密钥。” (reason: API_KEY_INVALID),因为谷歌回答一个未知的密钥; address_validation_denied 在未启用 API 的情况下给出密钥的 403 |
企业
59个地址:每行质量保证 ROUTING_ZIP_CORPUS (单位:千美元)packages/qa/src/world/gen/addresses.ts, (中文(简体) ),
+ DC, IDs),包括 凤凰AZ演示成员
(单位:千美元)ADDRESS_AT_HOME_PHLEBOTOMY:1625 N Central Ave, Phoenix, AZ 85004)等 (中文(简体) )
packages/app/src/test-addresses 成员,加 ADDRESS_AT_HOME_PHLEBOTOMY_2 (501 N 5th St.) (英语).
每一个都有其真正的县和城市的坐标. 位置标识是稳定的(ChIJ… 用于行;
合成地址获得一个 Ei… 正如Google自己的地址代号一样
细节不需要存储状态). GET /__admin/health 报告尸体.
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
GET /__admin/corpus | 命名空间的地址( 海关优先) 和自定义计数 . |
PUT /__admin/corpus | {addresses: [{line1, city, state, zip, id?, county?, lat?, lng?, validation?}]} 替换名称空间的自定义地址(在内建主体之上). validation 该行的 Pins 地址验证 : {granularity?, addressComplete?, possibleNextAction?, dpvConfirmation?: "Y"|"N"|"S"|"D", unconfirmedComponentTypes?, uspsErrorMessage?, multiUnit?, units?}。 。 。 . |
DELETE /__admin/corpus | 放弃自定义地址 . |
GET/PUT /__admin/settings | {keys?: string[], publicUrl?: string | null}。 。 。 . keys 限制已接受的 API 密钥( 其他获得) REQUEST_DENIED "提供的 API 密钥无效";缺失的密钥总是这样". publicUrl jS Shim在与请求不同时(重写代理). |
错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}· ; GET /__admin/faults/presets:
over_query_limit, (中文(简体) ), request_denied, (中文(简体) ), unknown_error, (中文(简体) ), zero_results (每个网络服务,HTTP 200)
以该地位, geocode_zero_results (行使我们的发现地倒置),
autocomplete_over_query_limit (其中两张是手动输入的), server_error
(HTTP 500), (韩语), slow (6 s,过去QA的5 s等),, script_unavailable (JS加载器回答503,所以)
剧本 onerror (见A/C.5/49/70,附件)。 只用于地址验证 : address_validation_denied (403) (中文(简体) )
PERMISSION_DENIED,没有启用 API 的密钥, address_validation_unavailable (503个)
UNAVAILABLE, (中文(简体) ), address_validation_slow (3 s, 超过2.5 s的结账超时),
address_validation_no_verdict (200个) {"result": {}}:不是谷歌发送的东西
客户端的防御分支)和 address_validation_dpv_n (日内瓦) N) (中文(简体) ). GET /__admin/metrics
计数 ValidateAddress 独自一人.
命名空间
x-mockingbird-namespace页:1 /__admin/ns/<name> 前缀在基址上(JS Shim服务于
前缀通过它回调),或 API 密钥:
PUT /__admin/credentials {"credentials": {"<PLACES_KEY>": "<namespace>"}} (单位:千美元) key 查询
参数,或 X-Goog-Api-Key 用于地址验证,是证书。 请求日记
记录操作、状态、解决 placeId 编辑 sessionToken,用于
ValidateAddress 解析的方块行 id (addressRowId和判决等级
(单位:千美元)ACCEPT/Y, (中文(简体) ), FIX/N;从未输入过地址.
测试
google-maps.property.test.ts:所有四种网络服务随机行走的自我均等(每一种) 和故意不同的情况 逮到他们了.google-maps.acceptance.test.ts驱动器test/consumer.ts我们的港口address-autocomplete-native-rest.tsx(URL建设者,解说者,两相相克相克相克相克相克相克相克相克相克相克相克相克相克相克相克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克 手动输入开关,parse-place-details.ts, (中文(简体) ),address-autocomplete-web.tsx财务报告和审定财务报表use-geocoded-address.ts(原始内容存档于2018-03-21) (通过在假窗口评价的shim). 也曾在HTTP服役.google-maps.address-validation.acceptance.test.ts: 每个地址验证判决等级, 400/403 信封、命名空间、日记和每个预设,通过test/consumer.ts是因为 测试失败的开口船对评估(non-2xx,无判决 = 无法使用;USPS) 错误,颗粒性,不完整,FIX编号 :CONFIRM_ADD_SUBPREMISES,批判性未经证实 组件,除DPVY编号 :S——拒绝). 自我平等包括:ValidateAddress。 。 。 .- 没有 SDK 滴入测试: 本地使用 plain
fetch,而网页 SDK 是谷歌的托管 剧本,shim取而代之. bun scripts/parity.ts: 现场对等maps.googleapis.com(和addressvalidation.googleapis.com页:1ValidateAddress与GOOGLE_MAPS_API_KEY(env / (中文(简体) ).env.local; 必须启用地址验证 键);2号出口没有它.
故意不模拟
- 案卷以外的地址:只有案卷行和街道合成了案卷城市
决心。 添加更多内容
PUT /__admin/corpus。 。 。 . - Google的路线扩展(
N Central Ave• 长名North Central Avenue:long_name重复了字母拼写,所以QA的一行一回转。 生活平等将显示这种差异. - 映射图( O)
google.maps.Map、标记、平板、静态地图、新地点 API (单位:千美元)places.googleapis.com, (中文(简体) ),Place班级,AutocompleteSuggestion),倒转地理编码 (单位:千美元)latlng=, (中文(简体) ),locationbias编号 :radius,以及超过预设的计费/配额. - 会话计费语义:接受并刊出符文,仅此而已.
- 地址验证
validateAddress数字 :provideValidationFeedback, (中文(简体) ),previousResponseId锁链,languageOptions财务报告和审定财务报表sessionToken(接受、忽视),metadata(业务/住宅/业务包厢),englishLatinAddress区域(无enableUspsCass他们得到一个FIX回答和无uspsData; Google 验证了许多国家). ZIP+4位数,dpvFootnote编码和USPS记录的其余部分(载货路线、交货) 点,县FIPS...) 被合成或省略:比较判决类和DPV代码,而不是 这些.
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
GoogleMapsAPI | 类 | 进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), corpus(), (中文(简体) ), state选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), publicNamespace, (中文(简体) ), corpus, (中文(简体) ), settings。 。 。 . |
createRuntime | 函数 | 全面服务合同的仿真器(保健、管理、命名空间、证书、预设和日记)。 选项 : corpus, (中文(简体) ), settings, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog。 。 。 . |
GOOGLE_MAPS_PRESETS | 对象 | 每个命名的断层预设. |
GOOGLE_MAPS_NAMESPACE | 字符串 | 服务名称, "google-maps"。 。 。 . |
keyCredential | 函数 | 这个 key 查询参数(或 X-Goog-Api-Key 请求头 (API 密钥映射到命名空间) . |
DEFAULT_CORPUS, (中文(简体) ), PHOENIX_DEMO_ADDRESS, (中文(简体) ), STATE_NAMES | 数值 | 地址表,凤凰城演示成员行,以及状态名称 administrative_area_level_1。 。 。 . |
corpusPlaceId | 函数 | 尸体行的固定位置. |
mapsJavaScript | 函数 | 绘制地图 JavaScript shim {base, key, authFailed, callback}。 。 。 . |
normalize | 函数 | 用于匹配的地址正常化 . |
MISSING_KEY_MESSAGE, (中文(简体) ), INVALID_KEY_MESSAGE | 字符串 | 谷歌的音乐 error_message 缺少 / 拒绝 密钥 . |
MISSING_API_KEY_MESSAGE, (中文(简体) ), INVALID_API_KEY_MESSAGE | 字符串 | 地址验证 error.message 缺少(403)/无效(400)密钥. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | OpenAPI合同及其操作代号. |
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务过来 node:http; 数据 serve CLI目标(--api-key, (中文(简体) ), --public-url; 第8814号口. |
部分 嘲笑鸟。 。 。 .