atlas_engine 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +506 -34
  3. data/app/countries/atlas_engine/be/country_profile.yml +2 -0
  4. data/app/countries/atlas_engine/be/validation_transcriber/address_parser.rb +84 -0
  5. data/app/countries/atlas_engine/bm/address_importer/corrections/open_address/city_alias_corrector.rb +12 -11
  6. data/app/countries/atlas_engine/bm/synonyms.yml +6 -0
  7. data/app/countries/atlas_engine/ch/country_profile.yml +2 -0
  8. data/app/countries/atlas_engine/ch/locales/de/country_profile.yml +0 -1
  9. data/app/countries/atlas_engine/ch/locales/fr/country_profile.yml +3 -0
  10. data/app/countries/atlas_engine/ch/locales/fr/validation_transcriber/address_parser.rb +29 -0
  11. data/app/countries/atlas_engine/cz/address_validation/es/query_builder.rb +43 -0
  12. data/app/countries/atlas_engine/cz/country_profile.yml +5 -1
  13. data/app/countries/atlas_engine/cz/validation_transcriber/address_parser.rb +26 -0
  14. data/app/countries/atlas_engine/es/country_profile.yml +3 -0
  15. data/app/countries/atlas_engine/es/synonyms.yml +2 -0
  16. data/app/countries/atlas_engine/es/validation_transcriber/address_parser.rb +28 -0
  17. data/app/countries/atlas_engine/fo/address_importer/corrections/open_address/city_corrector.rb +27 -0
  18. data/app/countries/atlas_engine/fo/country_profile.yml +4 -0
  19. data/app/countries/atlas_engine/fr/country_profile.yml +2 -0
  20. data/app/countries/atlas_engine/it/address_importer/open_address/mapper.rb +1 -1
  21. data/app/countries/atlas_engine/it/address_validation/validators/full_address/exclusions/city.rb +31 -0
  22. data/app/countries/atlas_engine/it/country_profile.yml +5 -0
  23. data/app/countries/atlas_engine/kr/address_validation/validators/full_address/exclusions/city.rb +69 -0
  24. data/app/countries/atlas_engine/kr/country_profile.yml +7 -0
  25. data/app/countries/atlas_engine/kr/validation_transcriber/address_parser.rb +36 -0
  26. data/app/countries/atlas_engine/lu/address_importer/corrections/open_address/city_corrector.rb +45 -0
  27. data/app/countries/atlas_engine/lu/country_profile.yml +4 -1
  28. data/app/countries/atlas_engine/lu/validation_transcriber/address_parser.rb +23 -0
  29. data/app/countries/atlas_engine/pl/address_importer/corrections/open_address/city_corrector.rb +25 -0
  30. data/app/countries/atlas_engine/pl/address_importer/corrections/open_address/empty_street_corrector.rb +32 -0
  31. data/app/countries/atlas_engine/pl/address_validation/exclusions/placeholder_postal_code.rb +35 -0
  32. data/app/countries/atlas_engine/pl/address_validation/exclusions/rural_address.rb +42 -0
  33. data/app/countries/atlas_engine/pl/country_profile.yml +13 -0
  34. data/app/countries/atlas_engine/pl/synonyms.yml +13 -0
  35. data/app/countries/atlas_engine/pl/validation_transcriber/address_parser.rb +36 -1
  36. data/app/countries/atlas_engine/pt/address_validation/validators/full_address/exclusions/zip.rb +38 -0
  37. data/app/countries/atlas_engine/pt/country_profile.yml +4 -0
  38. data/app/countries/atlas_engine/pt/synonyms.yml +12 -0
  39. data/app/countries/atlas_engine/pt/validation_transcriber/address_parser.rb +75 -0
  40. data/app/countries/atlas_engine/sa/country_profile.yml +4 -1
  41. data/app/countries/atlas_engine/si/address_importer/open_address/corrections/city_district_corrector.rb +25 -0
  42. data/app/countries/atlas_engine/si/address_importer/open_address/mapper.rb +19 -0
  43. data/app/countries/atlas_engine/si/address_validation/exclusions/unknown_city.rb +33 -0
  44. data/app/countries/atlas_engine/si/country_profile.yml +17 -0
  45. data/app/countries/atlas_engine/si/synonyms.yml +7 -0
  46. data/app/countries/atlas_engine/si/validation_transcriber/address_parser.rb +52 -0
  47. data/app/countries/atlas_engine/us/country_profile.yml +0 -2
  48. data/app/graphql/atlas_engine/schema.graphql +1 -1
  49. data/app/lib/atlas_engine/validation_transcriber/address_parser_base.rb +1 -1
  50. data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +1 -1
  51. data/app/lib/atlas_engine/validation_transcriber/formatter.rb +2 -2
  52. data/app/models/atlas_engine/address_validation/concern_record.rb +6 -1
  53. data/app/models/atlas_engine/address_validation/datastore_base.rb +3 -0
  54. data/app/models/atlas_engine/address_validation/es/datastore.rb +11 -6
  55. data/app/models/atlas_engine/address_validation/es/query_builder.rb +46 -30
  56. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +1 -1
  57. data/app/models/atlas_engine/address_validation/log_emitter.rb +1 -0
  58. data/app/models/atlas_engine/address_validation/normalizer.rb +0 -9
  59. data/app/models/atlas_engine/address_validation/statsd_emitter.rb +6 -2
  60. data/app/models/atlas_engine/address_validation/token/sequence/comparator.rb +38 -4
  61. data/app/models/atlas_engine/address_validation/token/sequence/comparison.rb +4 -4
  62. data/app/models/atlas_engine/address_validation/token/sequence/comparison_policy.rb +33 -0
  63. data/app/models/atlas_engine/address_validation/validators/full_address/address_comparison.rb +41 -31
  64. data/app/models/atlas_engine/address_validation/validators/full_address/building_comparison.rb +33 -0
  65. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +44 -18
  66. data/app/models/atlas_engine/address_validation/validators/full_address/city_comparison.rb +25 -0
  67. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +15 -6
  68. data/app/models/atlas_engine/address_validation/validators/full_address/exclusions/exclusion_base.rb +8 -2
  69. data/app/models/atlas_engine/address_validation/validators/full_address/field_comparison_base.rb +77 -0
  70. data/app/models/atlas_engine/address_validation/validators/full_address/province_code_comparison.rb +34 -0
  71. data/app/models/atlas_engine/address_validation/validators/full_address/relevant_components.rb +118 -0
  72. data/app/models/atlas_engine/address_validation/validators/full_address/street_comparison.rb +30 -0
  73. data/app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb +1 -1
  74. data/app/models/atlas_engine/address_validation/validators/full_address/zip_comparison.rb +37 -0
  75. data/app/models/atlas_engine/address_validation/validators/predicates/street/building_number_in_address1_or_address2.rb +2 -2
  76. data/app/models/atlas_engine/country_profile_validation_subset.rb +40 -2
  77. data/app/tasks/maintenance/atlas_engine/elasticsearch_index_create_task.rb +1 -1
  78. data/db/data/country_profiles/default.yml +12 -2
  79. data/lib/atlas_engine/version.rb +1 -1
  80. data/lib/tasks/atlas_engine/graphql.rake +13 -0
  81. metadata +42 -7
  82. data/app/models/atlas_engine/address_validation/validators/full_address/comparison_helper.rb +0 -135
  83. data/app/models/atlas_engine/address_validation/validators/full_address/components_to_validate.rb +0 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b097368a07bb9496c6c42c1ef98c785dc25ef5b3aa9d4a6bd97980ac372a8769
4
- data.tar.gz: b1383521f226975e0e48b2bd9ea03e3dc45b6903e66e245b7efff37e889b51cd
3
+ metadata.gz: ae2dfdcc902973978f88d2d0bcd07808dbde5c48eecfe53977c4449b422bd492
4
+ data.tar.gz: 5e2d0b59cdb714a01a5e1df904390253760046151be3fecddce1f69b3fa1cc28
5
5
  SHA512:
6
- metadata.gz: eb1337d027e93333a0f96ced70070a7c540b6d559d1e23490a2580965adc6cc87fd87bb0cb558962a32d306571bf154a70ba9edd36dfdbecbfd9f0f1372e1bb7
7
- data.tar.gz: cef1341af8b655e7eb701944308ad7c00ad1047d33c0f0a8866efe580fb0995736e4d8b5aa62d9dcd58daec468d3da7ef9ef0778bad4999e18b6a00da3f328dd
6
+ metadata.gz: 50b5daf2a3a65fe064d37fe3f54944b1300f6d80a5009447af0a96caaa191a67563a1f6964e96dfc3cf849e67ff9af1279bbd71f8f0dcf3cc8c64e86489b7dd6
7
+ data.tar.gz: cce398aa5d5389a01effce955b2b224b34593013064649afd833323e23afc8cf6a746b136cca3eb36b1fc33eb15c5f6cd30110f1f6c4585f6a17c935761e38c5
data/README.md CHANGED
@@ -1,12 +1,172 @@
1
- # Atlas Engine
1
+ # 🌐 Atlas Engine
2
+
3
+ Atlas Engine is a rails engine that provides a global end-to-end address validation API for rails apps.
4
+
5
+ * [Address Validation API](#address-validation-api)
6
+ * [Rails App Installation](#rails-app-installation)
7
+ * [Local Development Installation](#local-development-installation)
8
+ * [Address Data Ingestion](#address-data-ingestion)
9
+ * [Elasticsearch Matching Strategy](#elasticsearch-matching-strategy)
10
+
11
+ ## Address Validation API
12
+
13
+ The validation API is powered by GraphQL, an example request and explanation of the parameters and response follows:
14
+
15
+ ```graphql
16
+ query validation {
17
+ validation(
18
+ address: {
19
+ address1: "151 O'Connor St"
20
+ address2: ""
21
+ city: "Ottawa"
22
+ provinceCode: "ON"
23
+ countryCode: CA
24
+ zip: "K2P 2L8"
25
+ }
26
+ locale: "en"
27
+ matchingStrategy: LOCAL
28
+ ) {
29
+ validationScope
30
+ concerns {
31
+ code
32
+ fieldNames
33
+ suggestionIds
34
+ message
35
+ }
36
+ suggestions {
37
+ address1
38
+ address2
39
+ city
40
+ provinceCode
41
+ zip
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ Response:
48
+
49
+ ```json
50
+ {
51
+ "data": {
52
+ "validation": {
53
+ "validationScope": [
54
+ "country_code",
55
+ "province_code",
56
+ "zip",
57
+ "city",
58
+ "address1"
59
+ ],
60
+ "concerns": [],
61
+ "suggestions": []
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ **Address:** The raw input for each address line that is to be validated. Requirements for each field's format and even
68
+ presence or absence differs per country.
69
+
70
+ **Locale:** The language in which to render any messages in the validation API response.
71
+
72
+ **MatchingStrategy:** The strategy used to evaluate the validity of the address input. Out of the box, Atlas Engine
73
+ supports three different matching strategies: `local`, `es`, and `es_street`.
74
+ - `local` matching uses the [worldwide](https://github.com/Shopify/worldwide) gem to provide the most basic level of
75
+ address validation. This may include simple errors (required fields not populated) or more advanced errors (province
76
+ not belonging to the country, zip code not belonging to the province). This level of matching does not require
77
+ [ingestion](#ingestion) of country data to work, but the level of support and suggestions it can provide in its
78
+ responses is minimal.
79
+ - `es` matching uses data indexed in elasticsearch via our [ingestion](#ingestion) process to validate the city,
80
+ province, country, and zip code fields of the input address, in addition to all of the basic functionality provided
81
+ in the `local` strategy. A more detailed explanation for how this strategy works can be found [here](#elasticsearch-matching-strategy).
82
+ - `es_street` is our most advanced matching strategy and requires the highest quality data indexed in elasticsearch
83
+ via our [ingestion](#ingestion) process. This matching strategy provides everything that `es` and `local` does along
84
+ with validation of the address1 and address2 components of the address input. A more detailed explanation of how
85
+ this strategy works can be found [here](#elasticsearch-matching-strategy).
86
+
87
+ **Validation Scope:** This response object is populated with the field names from the input that have been successfully
88
+ validated.
89
+
90
+ **Concerns:** This response object is populated with a code if there is a validation error with the input address.
91
+ A concern may also include a suggestion to fix the issue.
92
+
93
+ **Suggestions:** This response object provides the corrected value for a field that has a concern if available.
94
+
95
+ ### Example request with a concern:
96
+
97
+ Navigate to http://localhost:3000/graphiql and initiate the following request. Note the invalid zip field.
98
+
99
+ ```graphql
100
+ query validation {
101
+ validation(
102
+ address: {
103
+ address1: "151 O'Connor St"
104
+ address2: ""
105
+ city: "Ottawa"
106
+ provinceCode: "ON"
107
+ countryCode: CA
108
+ zip: "90210"
109
+ }
110
+ locale: "en"
111
+ matchingStrategy: LOCAL
112
+ ) {
113
+ validationScope
114
+ concerns {
115
+ code
116
+ fieldNames
117
+ suggestionIds
118
+ message
119
+ }
120
+ suggestions {
121
+ address1
122
+ address2
123
+ city
124
+ provinceCode
125
+ zip
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ Response:
132
+
133
+ ```json
134
+ {
135
+ "data": {
136
+ "validation": {
137
+ "validationScope": [
138
+ "country_code",
139
+ "province_code",
140
+ "city",
141
+ "address1"
142
+ ],
143
+ "concerns": [
144
+ {
145
+ "code": "zip_invalid_for_province",
146
+ "fieldNames": [
147
+ "zip",
148
+ "country",
149
+ "province"
150
+ ],
151
+ "suggestionIds": [],
152
+ "message": "Enter a valid postal code for Ontario"
153
+ }
154
+ ],
155
+ "suggestions": []
156
+ }
157
+ }
158
+ }
159
+ ```
2
160
 
3
- This is a rails engine that is meant to provide end-to-end address validation for rails apps
161
+ The concerns object contains a concern code `zip_invalid_for_province` to highlight the validation error of `90210`
162
+ being an invalid zip code for the province `ON`. It also returns the human readable message
163
+ `"Enter a valid postal code for Ontario"` in the provided language `en`.
4
164
 
5
- ## Local Setup
165
+ The validation scope excludes zip because the zip was not successfully validated.
6
166
 
7
- ### In your rails app
167
+ ## Rails App Installation
8
168
 
9
- #### Initial setup
169
+ ### Initial setup
10
170
  Add the engine to your gemfile
11
171
  ```
12
172
  gem "atlas_engine"
@@ -19,7 +179,7 @@ bundle lock
19
179
  bin/rails generate atlas_engine:install
20
180
  ```
21
181
 
22
- #### Updating to a newer version of the engine
182
+ ### Updating to a newer version of the engine
23
183
 
24
184
  Working with migrations
25
185
  ```
@@ -30,9 +190,11 @@ rails atlas_engine:install:migrations
30
190
  rails db:migrate
31
191
  ```
32
192
 
33
- ### Developing in the engine
193
+ ## Local Development Installation
194
+
195
+ This setup guide is based on a mac os development environment. Your tooling may vary.
34
196
 
35
- #### Setup Docker
197
+ ### Install + Setup Docker
36
198
 
37
199
  ```
38
200
  brew install docker
@@ -46,62 +208,61 @@ colima start --cpu 4 --memory 8
46
208
  colima ssh
47
209
  sudo sysctl -w vm.max_map_count=262144
48
210
  exit
211
+ ```
212
+
213
+ Verify docker is running with: `docker info`
49
214
 
215
+ ### Clone the atlas_engine git repository
216
+
217
+ ```
218
+ git clone https://github.com/Shopify/atlas-engine.git
50
219
  ```
51
220
 
52
- Verify if docker is running: `docker info`
221
+ ### Setup Ruby and Rails
53
222
 
54
- #### Setup Rails
223
+ Install ruby >= 3.2.1
224
+
225
+ In the newly cloned repository directory run:
55
226
 
56
227
  ```
57
228
  bundle install
58
229
 
59
- # If you get an ssl error with puma installation run
230
+ # *Note* If you get an ssl error during the puma installation run the following command:
60
231
  bundle config build.puma --with-pkg-config=$(brew --prefix openssl@3)/lib/pkgconfig
61
232
  ```
62
233
 
63
- #### Setting up Elasticsearch, Mysql
234
+ ### Setup up Dockerized Elasticsearch and MySQL
64
235
 
236
+ In a separate terminal, from the cloned atlas_engine directory run:
65
237
  ```
66
- bash setup
67
238
  docker-compose up
68
239
 
69
- # If you encounter an error getting docker credentials, remove or update the `credsStore`
240
+ # *Note* If you encounter an error getting docker credentials, remove or update the `credsStore`
70
241
  key in your Docker configuration file:
71
242
 
72
243
  # ~/.docker/config.json
73
244
  "credsStore": "desktop", # remove this line
74
245
  ```
75
246
 
76
- Connecting to Docker services
77
- * for Mysql : `mysql --host=127.0.0.1 --user=user --password=changeme`
78
- * for Elasticsearch : `http://localhost:9200`
79
-
80
- _note: if you have updated any of the ports in your .env file then use those ports instead_
81
-
247
+ Verify your connection to the newly created Docker services with the following commands:
248
+ - MySQL : `mysql --host=127.0.0.1 --user=root`
249
+ - Elasticsearch : `curl http://localhost:9200`
82
250
 
83
- #### Setting up db
251
+ ### Setup the local db
84
252
  ```
85
253
  rails db:setup
86
254
  ```
87
255
 
88
- #### Setting up maintenance tasks
89
- After locally setting up Atlas Engine:
90
- ```
91
- rails app:maintenance_tasks:install:migrations
92
- rails db:migrate
93
- ```
94
-
95
- ## Using the App
96
-
97
256
  ### Infrastructure Requirements
98
- The elasticsearch implementation depends on the ICU analysis plugin. Refer to the [Dockfile](./Dockfile) leveraged in local setup for plugin installation.
257
+ The elasticsearch implementation depends on the ICU analysis plugin. Refer to the [Dockerfile](./docker/elasticsearch/Dockerfile) leveraged in local setup for plugin installation.
99
258
 
100
- ### Starting the App and Testing
259
+ ### Starting the App / Running Tests
101
260
  * `bin/rails server` to start the server
102
261
  * `bin/rails test` to run tests
262
+ * `bundle exec rubocop` to run ruby style checks
263
+ * `src tc` to run sorbet typechecks
103
264
 
104
- ### Running Sorbet
265
+ ### Sorbet
105
266
 
106
267
  Generate rbi files for custom code
107
268
  ```
@@ -117,7 +278,318 @@ bin/tapioca gems
117
278
  bin/tapioca gems --all
118
279
  ```
119
280
 
120
- Running a sorbet check
281
+ Run sorbet check
121
282
  ```
122
283
  srb tc
123
284
  ```
285
+
286
+ ## Address Data Ingestion
287
+
288
+ In order to power the more advanced validation matching strategies that provide city / state / zip and even street
289
+ level address validation, your app must have a populated elasticsearch index per country available for `atlas_engine`
290
+ to query.
291
+
292
+ The data we use to power atlas engine validation is free open source data from the [open addresses](https://openaddresses.io/)
293
+ project. The following guide demostrates how to ingest data with the dummy app, but the process is the same with
294
+ the engine mounted into your own rails app.
295
+
296
+ 1. Go to the [open addresses](https://openaddresses.io/) download center, create an account, support the project, and
297
+ download a GeoJSON+LD file for the country or region you wish to validate. For this example, we will be using the
298
+ countrywide addresses data for Australia.
299
+
300
+ 2. Once the file is downloaded, start your app with `rails s` and navigate to `http://localhost:3000/maintenance_tasks`
301
+ (see [the github repo](https://github.com/Shopify/maintenance_tasks) for more information about maintenance_tasks).
302
+ There are two tasks available: `Maintenance::AtlasEngine::GeoJsonImportTask` and `Maintenance::AtlasEngine::ElasticsearchIndexCreateTask`. We will be using both in the ingestion process.
303
+
304
+ 3. Navigate to the `Maintenance::AtlasEngine::GeoJsonImportTask`. This task will transform the raw geo json file into
305
+ records in our mysql database and has the following parameters:
306
+
307
+ - **clear_records:** If checked, removes any existing records for the country in the database.
308
+
309
+ - **country_code: (required)** The ISO country code of the data we are ingesting.
310
+ In this example, the country code of Australia is `AU`.
311
+
312
+ - **geojson_file_path: (required)** The fully qualified path of the previously downloaded geojson data from open addresses.
313
+
314
+ - **locale: (optional)** The language of the data in the open addresses file.
315
+
316
+ 4. Once properly parameterized, click run. The process will initialize a `country_import` and should succeed immediately.
317
+
318
+ 5. Navigate to `http://localhost:3000/country_imports` to track the progress of the country import. Click the import id
319
+ link for a more detailed view. Once the import status has updated from `in_progress` to `complete` we will have all of
320
+ the raw open address data imported into our mysql database's `atlas_engine_post_addresses` table.
321
+
322
+ 6. Navigate back to `http://localhost:3000/maintenance_tasks` and click on the `Maintenance::AtlasEngine::ElasticsearchIndexCreateTask`. This task will ingest the data we have staged in mysql
323
+ and use it to create documents in a new elasticsearch index which Atlas Engine will ultimately use for validation.
324
+
325
+ 7. The `ElasticsearchIndexCreateTask` includes the following parameters:
326
+
327
+ - **country_code: (required)** the ISO country code of the data we are ingesting and the name of the elasticsearch index we
328
+ will be creating. In this example, the country code of Australia is `AU`.
329
+
330
+ - **locale: (optional)** the language of the documents we will be creating. This is required for multi-locale countries
331
+ as our indexes are separated by language.
332
+
333
+ - **province_codes: (optional)** an allow list of province codes to create documents for. If left blank the task will create
334
+ documents for the entire dataset.
335
+
336
+ - **shard_override: (optional)** the number of shards to create this index with. If left blank the default will be used.
337
+
338
+ - **replica_override: (optional)** the number of replicas to create this index with. If left blank the default will be used.
339
+
340
+ - **activate_index: (optional)** if checked, immediately promote this index to be the index queried by atlas engine.
341
+ If unchecked, the created index will need to be activated manually.
342
+
343
+ 8. Once properly parameterized, click run. The maintenance task UI will track the progress of the index creation.
344
+
345
+ 9. When completed, the index documents may be verified manually with an elasticsearch client.
346
+ We may now use the `es` and `es_street` matching strategies with `AU` addresses. See [below](#elasticsearch-matching-strategy)
347
+ for an example of its usage.
348
+
349
+ ## Elasticsearch Matching Strategy
350
+
351
+ Once we have successfully created and activated an elasticsearch index using open address data, we may now use
352
+ the more advanced elasticsearch matching strategies `es` and `es_street`.
353
+
354
+ Consider the following example of an invalid `AU` address:
355
+
356
+ ```graphql
357
+ query validation {
358
+ validation(
359
+ address: {
360
+ address1: "100 miller st"
361
+ address2: ""
362
+ city: "sydney"
363
+ provinceCode: "NSW"
364
+ countryCode: AU
365
+ zip: "2060"
366
+ }
367
+ locale: "en"
368
+ matchingStrategy: ES
369
+ ) {
370
+ validationScope
371
+ concerns {
372
+ code
373
+ fieldNames
374
+ suggestionIds
375
+ message
376
+ }
377
+ suggestions {
378
+ address1
379
+ address2
380
+ city
381
+ provinceCode
382
+ zip
383
+ }
384
+ }
385
+ }
386
+ ```
387
+
388
+ When input into `http://localhost:3000/graphiql`, this query should produce the following response:
389
+
390
+ ```json
391
+ {
392
+ "data": {
393
+ "validation": {
394
+ "candidate": ",NSW,,,,2060,[North Sydney],,Miller Street",
395
+ "validationScope": [
396
+ "country_code",
397
+ "province_code",
398
+ "zip",
399
+ "city",
400
+ "address1"
401
+ ],
402
+ "concerns": [
403
+ {
404
+ "code": "city_inconsistent",
405
+ "typeLevel": 3,
406
+ "fieldNames": [
407
+ "city"
408
+ ],
409
+ "suggestionIds": [
410
+ "665ffd09-75b8-584d-8e4a-a0f471bfea01"
411
+ ],
412
+ "message": "Enter a valid city for New South Wales, 2060"
413
+ }
414
+ ],
415
+ "suggestions": [
416
+ {
417
+ "id": "665ffd09-75b8-584d-8e4a-a0f471bfea01",
418
+ "address1": null,
419
+ "address2": null,
420
+ "city": "North Sydney",
421
+ "province": null,
422
+ "provinceCode": null,
423
+ "zip": null
424
+ }
425
+ ]
426
+ }
427
+ }
428
+ }
429
+ ```
430
+
431
+ The concerns object contains a concern code `city_inconsistent` to highlight the validation error of `sydney`
432
+ being an incorrect city for the rest of the provided address. The concern message field is the human readable
433
+ error nudge `"Enter a valid city for New South Wales, 2060"`, pointing to the supporting pieces of evidence (province
434
+ and zip) that were used to determine city as the inconsistent value in this address input.
435
+
436
+ The suggestion object contains a corrected city field `North Sydney` which will result in no concerns or suggestions
437
+ for the validation endpoint if applied.
438
+
439
+ The candidate field contains a representation of the matching document in the elasticsearch index that was found and
440
+ used to determine the suggestions and concerns in the api response.
441
+
442
+ The `es_street` level of validation can also be used to correct errors in the `address1` or `address2` fields of the
443
+ input. In the following request we have modified our query to make a second error in our input - searching for
444
+ `miller ave` instead of `miller st`.
445
+
446
+ ```graphql
447
+ query validation {
448
+ validation(
449
+ address: {
450
+ address1: "100 miller ave"
451
+ address2: ""
452
+ city: "sydney"
453
+ provinceCode: "NSW"
454
+ countryCode: AU
455
+ zip: "2060"
456
+ }
457
+ locale: "en"
458
+ matchingStrategy: ES_STREET
459
+ ) {
460
+ validationScope
461
+ concerns {
462
+ code
463
+ fieldNames
464
+ suggestionIds
465
+ message
466
+ }
467
+ suggestions {
468
+ address1
469
+ address2
470
+ city
471
+ provinceCode
472
+ zip
473
+ }
474
+ }
475
+ }
476
+ ```
477
+
478
+ This query produces the following response:
479
+
480
+ ```json
481
+ {
482
+ "data": {
483
+ "validation": {
484
+ "candidate": ",NSW,,,,2060,[North Sydney],,Miller Street",
485
+ "validationScope": [
486
+ "country_code",
487
+ "province_code",
488
+ "zip",
489
+ "city",
490
+ "address1"
491
+ ],
492
+ "concerns": [
493
+ {
494
+ "code": "city_inconsistent",
495
+ "typeLevel": 3,
496
+ "fieldNames": [
497
+ "city"
498
+ ],
499
+ "suggestionIds": [
500
+ "88779db6-2c5d-5dbb-9f77-f7b07c07206a"
501
+ ],
502
+ "message": "Enter a valid city for New South Wales, 2060"
503
+ },
504
+ {
505
+ "code": "street_inconsistent",
506
+ "typeLevel": 3,
507
+ "fieldNames": [
508
+ "address1"
509
+ ],
510
+ "suggestionIds": [
511
+ "88779db6-2c5d-5dbb-9f77-f7b07c07206a"
512
+ ],
513
+ "message": "Enter a valid street name for New South Wales, 2060"
514
+ }
515
+ ],
516
+ "suggestions": [
517
+ {
518
+ "id": "88779db6-2c5d-5dbb-9f77-f7b07c07206a",
519
+ "address1": "100 Miller Street",
520
+ "address2": null,
521
+ "city": "North Sydney",
522
+ "province": null,
523
+ "provinceCode": null,
524
+ "zip": null
525
+ }
526
+ ]
527
+ }
528
+ }
529
+ }
530
+ ```
531
+
532
+ The concerns object now contains an additional concern code `street_inconsistent` to highlight the validation error of
533
+ `miller ave` being an incorrect street for the rest of the address input. The concern message field is the human
534
+ readable error nudge `"Enter a valid street name for New South Wales, 2060"`, pointing to the supporting pieces of
535
+ evidence (province and zip) that were used to determine street as an inconsistent value in this address input.
536
+
537
+ The suggestion object contains a corrected street field `100 Miller Street` and a corrected city field `North Sydney`
538
+ If both of these suggestions are applied to the input address the subsequent request will be valid.
539
+
540
+ The corrected input of
541
+
542
+ ```graphql
543
+ query validation {
544
+ validation(
545
+ address: {
546
+ address1: "100 miller st"
547
+ address2: ""
548
+ city: "north sydney"
549
+ provinceCode: "NSW"
550
+ countryCode: AU
551
+ zip: "2060"
552
+ }
553
+ locale: "en"
554
+ matchingStrategy: ES_STREET
555
+ ) {
556
+ validationScope
557
+ concerns {
558
+ code
559
+ fieldNames
560
+ suggestionIds
561
+ message
562
+ }
563
+ suggestions {
564
+ address1
565
+ address2
566
+ city
567
+ provinceCode
568
+ zip
569
+ }
570
+ }
571
+ }
572
+ ```
573
+
574
+ will produce the response:
575
+
576
+ ```json
577
+ {
578
+ "data": {
579
+ "validation": {
580
+ "candidate": ",NSW,,,,2060,[North Sydney],,Miller Street",
581
+ "validationScope": [
582
+ "country_code",
583
+ "province_code",
584
+ "zip",
585
+ "city",
586
+ "address1"
587
+ ],
588
+ "concerns": [],
589
+ "suggestions": []
590
+ }
591
+ }
592
+ }
593
+ ```
594
+
595
+ This response has no concerns or suggestions, and the input address is therefore considered to be valid.
@@ -6,6 +6,8 @@ ingestion:
6
6
  validation:
7
7
  enabled: true
8
8
  default_matching_strategy: local
9
+ address_parser: AtlasEngine::Be::ValidationTranscriber::AddressParser
10
+ has_provinces: false
9
11
  index_locales:
10
12
  - fr
11
13
  - nl