Geoclient is software which provides developer-friendly API’s for geocoding New York City location information by proxying requests to Geosupport which is the City’s official geocoder of record.

1. Concepts

This section describes the purpose and high-level design of this project.


Once upon a time, the developers at the City of New York’s OTI/GIS (formerly DoITT/DMI/GIS) found themselves repeatedly copying a fairly large amount of platform-specific Java/JNI and C client code between their own projects which depended on Geosupport for geocoding services.

Geoclient was built to provide a simplified service API for interacting with Geosupport from any runtime capable of making simple HTTP GET requests. In other words, Geoclient is just a proxy API for calling Geosupport which works dilligently behind the scenes doing the actual geocoding with its own data carefully researched and maintained by the Department of City Planning.

Geoclient itself contains no additional spatial logic or reference data and by design tries only to make it easier for applications to call Geosupport. The one exception is the /search endpoint which adds NYC location-aware, natural language parsing functionality appropriate for user-driven, "single-field search" e.g., via Ajax calls from an web page. See Section FIXME for details.

Runtime
Figure 1. The Big Picture
Important

Although, the names are similar, Geoclient and Geosupport are completely different applications built and maintained by two different teams:

It is important to understand that these are distinct software projects because Geoclient's primary purpose is to make it easier to use the Geosupport geocoder. In this way, Geoclient presents an intuitive, simplified facade but is not itself a geocoder.

2. REST API

This section documents how to call the Geoclient REST API and provides example requests and responses.


The Geoclient service provides the following endpoints:

Table 1. Endpoints
Type Description Geosupport Function

Address

Given a valid address, provides blockface-level, property-level, and political information (source).

1B[1]

Address Point

"Function AP finds the address point for a given address. Address points are point locations located approximately five feet inside the building along the corresponding street frontage. Address points do not exist for all administrative address ranges assigned to a building, but usually only reflect the posted address." (source)

AP[2]

BBL

Given a valid borough, block, and lot provides property-level information. (source)

BL[3]

BIN

Given a valid building identification number provides property-level information. (source)

BN[4]

Blockface

Given a valid borough, "on street" and cross streets provides blockface-level information. (source)

3[5], 3X[6]

Intersection

Given a valid borough and cross streets returns information for the point defined by the two streets. (source)

2[7], 2W[8]

Place

Same as 'Address' above using well-known NYC place name for input (instead of a house number and street).

1B[1]

Search

Provides parsing and search algorithm customization for several of the other endpoints listed in this section. Typically used for geocoding unstructured text to support "single-field" user searches. See the Search section below for details.

Address, BBL, BIN, Blockface, Intersection, Place

Streetcode

Translates a Geosupport street code (B5SC, B7SC, or B10SC) to a street name with the corresponding B10SC.

See Geosupport Street Name Functions.

Normalize

Normalizes a street name but does not verify that it actually exists. (source)

See Geosupport Street Name Functions.

Version

Provides software version information about the Geoclient endpoint itself and Geosupport version/release info directly from the Geosupport instance this endpoint is currently using.

HR (undocumented Geosupport metadata function)

2.1. Calling the Geoclient API

2.1.1. Requests

All requests are made as simple HTTP GET requests with input arguments specified as URL query string and/or request parameters. The service returns the JSON (application/json) media type by default unless a Content-Type header or the .xml file extension is appended as a request parameter to the endpoint function.

/search?input=100%20centre%20street%20manhattan (1)

/search.json?input=100%20centre%20street%20manhattan (2)
       ^^^^^

/search.xml?input=100%20centre%20street%20manhattan (3)
       ^^^^
  1. Returns application/json (default)

  2. Returns application/json

  3. Returns application/xml

Warning
In the example above, (2) and (3) use file extensions as request (path) parameters. This functionality is deprecated and will eventually be removed from Geoclient. In future versions, adding a Content-Type header or an HTTP query string parameter will be the way to request a non-default media type.

2.1.2. Responses

Any response from Geoclient is composed almost entirely from the results of the proxied Geosupport function call. This documentation no longer attempts to provide in-depth information about these functions. Instead, links are provided to the Department of City Planning’s detailed documentation about their geocoding logic and return data.

Here’s some high-level guidelines that will allow your code to remain loosely coupled with this API:

  • By default, Geoclient does not serialize fields returned from Geosupport with NULL values in order to reduce unecessary network I/O. The responses shown below are for example purposes only and do not include all possible fields that may be returned.

  • Even for successfully recognized input, certain data attributes may not be available for some locations. Similarly, some attributes only make sense for certain input types.

  • Although the examples are "pretty-printed" in this document, calling applications should not depend on any particular formatting of responses.

  • The order of returned data elements is unspecified.

  • Client code which parses the structured text of a Geoclient response should not rely upon significant whitespace or element/attribute ordering.

  • However, the field values returned by Geosupport sometimes do contain significant whitespace or formatting which Geoclient intentionally leaves unchanged.

  • Occasionally, Geosupport fails to recognize a valid location or there is a bug in the Geoclient code. See Section FIXME for information on when and how to contact the appropriate team.

2.2. Common query string and request parameters

The following request parameters are required for all operations (except where noted):

Case sensitivity

The Geoclient base URI and query parameter names are case-sensitive!

# valid
/geoclient/v2/address?houseNumber=2826&street=broadway&borough=manhattan
# invalid
/Geoclient/v2/address?houseNumber=2826&street=broadway&borough=manhattan
 ^
/geoclient/v2/address?houseNumber=2826&Street=broadway&borough=manhattan
                                       ^

However, parameter values are not case-sensitive.

# valid
/geoclient/v2/address?houseNumber=2826&street=BROADWAY&borough=Manhattan
                               These are ok:  ^^^^^^^^         ^

2.2.1. Borough

The borough parameter can either be a borough name or a borough number. Borough names are not case-sensitive.

Table 2. Valid Values

Borough

By name

By number

Manhattan

  • Manhattan

  • MN

1

Bronx

  • Bronx

  • BX

  • The Bronx

2

Brooklyn

  • Brooklyn

  • BK

  • BKLYN

3

Queens

  • Queens

  • QN

4

Staten Island

  • Staten Island

  • SI

  • STATENISLAND

  • STATENIS

5

The preceeding table describes borough values recognized by Geosupport. The Geoclient /search endpoint some additional aliases to improve the parsing of single-field searches.

Recognized as Manhattan:

`NEW YORK`
`NEW YORK CITY`
`N.Y.C.`
`NYC`
`N.Y.`
`NY`

Recognized as Queens:

Arverne
Astoria
Bayside
Bellerose
Breezy Point
Cambria Heights
College Point
Corona
East Elmhurst
Elmhurst
Far Rockaway
Floral Park
Flushing
Forest Hills
Fresh Meadows
Glen Oaks
Hollis
Howard Beach
Inwood
Jackson Heights
Jamaica
Kew Gardens
Little Neck
Long Island City
Maspeth
Middle Village
New Hyde Park
Oakland Gardens
Ozone Park
Qs
Queens Village
Rego Park
Richmond Hill
Ridgewood
Rockaway Park
Rosedale
Saint Albans
South Ozone Park
South Richmond Hill
Springfield Gardens
Sunnyside
Whitestone
Woodhaven
Woodside

2.3. Understanding Geoclient Response Status

There are two ways in which the Geoclient service communicates call status information: HTTP status codes and Geosupport return codes.

2.3.1. HTTP Status Codes

Clients calling the service will always receive an HTTP status code, either from the service or (e.g., if a connection cannot be made) from the HTTP protocol implementation itself.

Full documentation of possible HTTP status codes are beyond the scope of this document, but Mozilla provides an easy to understand reference site. For more detailed information, please see section 15 of RFC 9110.

In brief, here are the most commonly returned HTTP status codes:

Table 3. Common HTTP Status Codes

HTTP Status Code

Meaning

200

The call successfully reached the Geoclient application (See Geosupport Return Codes for the status of the actual geocoding attempt).

400

A required query parameter is missing. See for information on call parameters.

401

Unauthorized: indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

403

Forbidden: The HTTP 403 Forbidden client error status response code indicates that the server understood the request but refuses to authorize it.

404

An incorrect URL has been used. There is no service mapped to it.

500

The Geoclient service could not process the request due to an internal server error.

2.3.2. Geosupport Return Codes

The Geosupport application uses return codes, reason codes, and messages to indicate the processing status of a given function call.

Note
Return codes come directly from the Geosupport application; as mentioned above, the Geoclient service uses standard HTTP status codes to report on it’s own request processing.

These return codes are often highly specific to a given function or processing state and there are many of them. This section describes only a very high-level summary of their meaning.

Please see DCP’s official return code documentation for a complete explanation.

The following table summarizes the meaning of the codes returned by

Table 4. Geosupport Return Codes

Return Code

Description

Response Fields

00

Success

geosupportReturnCode, (reasonCode and message will be blank)

01

Success with warnings

geosupportReturnCode, reasonCode, message

GRC greater than 01

Reject or error

geosupportReturnCode, reasonCode, message

Some Geosupport functions are actually just the combined results of two "sub-function" calls. At this time, function 1B (exposed by the Geoclient /address endpoint) is the only case where this applies.

Results returned by function 1B are composed of calls to functions 1EX(theoretical address that may or may not exist in reality computed using the house number range based off of segment information from the street’s centerline) and 1AX (real address and associated property-level information based on tax lot information).

Function 1B

Although it is uncommon, there are a significant number of locations where data is valid and/or available for only one of these two sub-function calls. Therefore, please check the following fields when calling Geoclient’s address endpoint:

Table 5. Function B Sub-functions

1B Sub-function

Field

Alias

1EX

geosupportReturnCode

returnCode1e

1EX

reasonCode

reasonCode1e

1EX

message

1AX

geosupportReturnCode2

returnCode1a

1AX

reasonCode2

reasonCode1a

1AX

message2

2.4. Geosupport Street Name Functions

Geosupport has a rich model for streets and provides many functions and flags to support street processing. Geoclient supports calls to functions D, DG, and DN with the /streetcode endpoint and function N with the /normalize function.

The /streetcode endpoint calls different Geosupport functions depending on the type of street code given for the streetCode, streetCodeTwo, streetCodeThree parameters:

Table 6. /streetcode endpoint’s use of Geosupport functions

Street Code Type

Geosupport Function

B5SC

Function D

B7SC

Function DG

B10SC

Function DN

For a high-level overview of street code handling in Geosupport see the Street (Name / Code) section on this page.

This document describes the Geoclient API for calling these functions but not a description of what they do and how to use them. For that, DCP provides the (drum roll please…​) Geosupport System User Programming Guide. For working with the /normalize endpoint, the reading following sections is probably enough to get you started:

To work effectively with the streetcode endpoint (i.e., functions D, DG, DN), you’ll probably want to look through the following chapters:

The Geosupport input API used by the Geoclient /normalize and /streetcode endpoints is documented here.

2.5. Examples

For examples of calling Geoclient programmatically, see the geoclient-examples repository on GitHub.

3. Endpoints

3.1. Address

Path: /v2/address

Parameters:

Table 7. /address arguments
Parameter Name Required/Optional Comments

houseNumber

required

House number of the address.

street

required

Street name or 7-digit street code.

borough

required if zip is not given

Valid values defined in Borough.

zip

required if borough is not given

Standard USPS 5-digit zip code or zip+4 (see this article). Must be a valid zip code for an area within New York City limits.

Example Requests:

Request:

/geoclient/v2/address?houseNumber=314&street=w%20100%20st&borough=manhattan
Show JSON
{
    "address": {
        "alleyCrossStreetsFlag": "X",
        "assemblyDistrict": "69",
        "bbl": "1018887502",
        "bblBoroughCode": "1",
        "bblTaxBlock": "01888",
        "bblTaxLot": "7502",
        "blockfaceId": "1322604631",
        "boardOfElectionsPreferredLgc": "1",
        "boePreferredStreetName": "WEST  100 STREET",
        "boePreferredstreetCode": "13577001",
        "boroughCode1In": "1",
        "buildingIdentificationNumber": "1057093",
        "cdta2020": "MN07",
        "censusBlock2000": "6000",
        "censusBlock2010": "2000",
        "censusBlock2020": "2000",
        "censusTrack2020": " 187  ",
        "censusTract1990": " 187  ",
        "censusTract2000": " 187  ",
        "censusTract2010": " 187  ",
        "censusTract2020": " 187  ",
        "cityCouncilDistrict": "07",
        "civilCourtDistrict": "05",
        "coincidentSegmentCount": "1",
        "communityDistrict": "107",
        "communityDistrictBoroughCode": "1",
        "communityDistrictNumber": "07",
        "communitySchoolDistrict": "03",
        "condominiumBillingBbl": "1018887502",
        "condominiumFlag": "C",
        "congressionalDistrict": "12",
        "cooperativeIdNumber": "0000",
        "crossStreetNamesFlagIn": "E",
        "dcpPreferredLgc": "01",
        "dcpZoningMap": "5D",
        "dofCondominiumIdentificationNumber": "1981",
        "dotStreetLightContractorArea": "1",
        "dynamicBlock": "601",
        "electionDistrict": "045",
        "fireBattalion": "11",
        "fireCompanyNumber": "022",
        "fireCompanyType": "L",
        "fireDivision": "03",
        "firstBoroughName": "MANHATTAN",
        "firstStreetCode": "13577001010",
        "firstStreetNameNormalized": "WEST  100 STREET",
        "fromActualSegmentNodeId": "9051124",
        "fromLionNodeId": "0023422",
        "fromPreferredLgcsFirstSetOf5": "01",
        "genericId": "0167324",
        "geosupportFunctionCode": "1B",
        "geosupportReturnCode": "00",
        "geosupportReturnCode2": "00",
        "gi5DigitStreetCode1": "35770",
        "giBoroughCode1": "1",
        "giBuildingIdentificationNumber1": "1057093",
        "giDcpPreferredLgc1": "01",
        "giHighHouseNumber1": "316",
        "giLowHouseNumber1": "314",
        "giSideOfStreetIndicator1": "L",
        "giStreetCode1": "13577001",
        "giStreetName1": "WEST  100 STREET",
        "healthArea": "3110",
        "healthCenterDistrict": "16",
        "highBblOfThisBuildingsCondominiumUnits": "1018881233",
        "highCrossStreetB5SC1": "129690",
        "highCrossStreetCode1": "12969001",
        "highCrossStreetName1": "RIVERSIDE DRIVE",
        "highHouseNumberOfBlockfaceSortFormat": "000398000AA",
        "houseNumber": "314",
        "houseNumberIn": "314",
        "houseNumberSortFormat": "000314000AA",
        "hurricaneEvacuationZone": "X",
        "individualSegmentLength": "00118",
        "instructionalRegion": "MN",
        "interimAssistanceEligibilityIndicator": "I",
        "internalLabelXCoordinate": "0991892",
        "internalLabelYCoordinate": "0230017",
        "latitude": 40.798178,
        "latitudeInternalLabel": 40.798017,
        "legacySegmentId": "0037349",
        "lionBoroughCode": "1",
        "lionBoroughCodeForVanityAddress": "1",
        "lionFaceCode": "5345",
        "lionFaceCodeForVanityAddress": "5345",
        "lionKey": "1534500065",
        "lionKeyForVanityAddress": "1534500065",
        "lionSequenceNumber": "00065",
        "lionSequenceNumberForVanityAddress": "00065",
        "listOf4Lgcs": "01",
        "longitude": -73.972225,
        "longitudeInternalLabel": -73.972399,
        "lowBblOfThisBuildingsCondominiumUnits": "1018881201",
        "lowCrossStreetB5SC1": "144990",
        "lowCrossStreetCode1": "14499001",
        "lowCrossStreetName1": "WEST END AVENUE",
        "lowHouseNumberOfBlockfaceSortFormat": "000300000AA",
        "lowHouseNumberOfDefiningAddressRange": "000314000AA",
        "noCrossStreetCalculationFlag": "Y",
        "nta": "MN12",
        "nta2020": "MN0703",
        "numberOfCrossStreetB5SCsHighAddressEnd": "1",
        "numberOfCrossStreetB5SCsLowAddressEnd": "1",
        "numberOfCrossStreetsHighAddressEnd": "1",
        "numberOfCrossStreetsLowAddressEnd": "1",
        "numberOfEntriesInListOfGeographicIdentifiers": "0001",
        "numberOfExistingStructuresOnLot": "0001",
        "numberOfParkingLanesOnTheStreet": "2",
        "numberOfStreetFrontagesOfLot": "01",
        "numberOfTotalLanesOnTheStreet": "3",
        "numberOfTravelLanesOnTheStreet": "1",
        "physicalId": "0181278",
        "policePatrolBoroughCommand": "2",
        "policePrecinct": "024",
        "policeSector": "24A",
        "pumaCode": "03806",
        "returnCode1a": "00",
        "returnCode1e": "00",
        "roadwayType": "1",
        "rpadBuildingClassificationCode": "R4",
        "rpadSelfCheckCodeForBbl": "5",
        "sanbornBoroughCode": "1",
        "sanbornPageNumber": "034",
        "sanbornVolumeNumber": "07",
        "sanbornVolumeNumberSuffix": "S",
        "sanitationBulkPickupSchedule": "ETHS",
        "sanitationCollectionSchedulingSectionAndSubsection": "5R",
        "sanitationCommercialWasteZone": "MN5",
        "sanitationDistrict": "107",
        "sanitationRecyclingCollectionSchedule": "ET",
        "sanitationRegularCollectionSchedule": "TTHS",
        "sanitationSection": "075",
        "sanitationSnowPriorityCode": "H",
        "segmentAzimuth": "151",
        "segmentIdentifier": "0310083",
        "segmentLengthInFeet": "00574",
        "segmentOrientation": "W",
        "segmentTypeCode": "U",
        "selfCheckCodeOfBillingBbl": "5",
        "sideOfStreetIndicator": "L",
        "sideOfStreetOfVanityAddress": "L",
        "speedLimit": "25",
        "splitLowHouseNumber": "000314000AA",
        "stateSenatorialDistrict": "47",
        "streetName1In": "W 100 ST",
        "streetStatus": "2",
        "streetWidth": "30",
        "streetWidthMaximum": "30",
        "taxMapNumberSectionAndVolume": "10703",
        "toActualSegmentNodeId": "9051125",
        "toLionNodeId": "0023852",
        "toPreferredLgcsFirstSetOf5": "01",
        "trafficDirection": "A",
        "underlyingStreetCode": "13577001",
        "uspsPreferredCityName": "NEW YORK",
        "workAreaFormatIndicatorIn": "C",
        "xCoordActualSegmentHighAddressEnd": "0991854",
        "xCoordActualSegmentLowAddressEnd": "0991957",
        "xCoordinate": "0991940",
        "xCoordinateHighAddressEnd": "0991683",
        "xCoordinateLowAddressEnd": "0992186",
        "xCoordinateOfCenterofCurvature": "0000000",
        "yCoordActualSegmentHighAddressEnd": "0230127",
        "yCoordActualSegmentLowAddressEnd": "0230070",
        "yCoordinate": "0230076",
        "yCoordinateHighAddressEnd": "0230221",
        "yCoordinateLowAddressEnd": "0229944",
        "yCoordinateOfCenterofCurvature": "0000000",
        "zipCode": "10025"
    }
}

3.2. Address Point

Path: /v2/addresspoint

Parameters:

Same as the Address endpoint.

Example Requests:

Request:

/geoclient/v2/addresspoint?houseNumber=314&street=w%20100%20st&borough=manhattan
Show JSON
{
    "addresspoint": {
        "addressPointId": "001047354",
        "bbl": "1018887502",
        "bblBoroughCode": "1",
        "bblTaxBlock": "01888",
        "bblTaxLot": "7502",
        "boroughCode1In": "1",
        "buildingIdentificationNumber": "1057093",
        "condominiumBillingBbl": "1018887502",
        "condominiumFlag": "C",
        "dofCondominiumIdentificationNumber": "1981",
        "firstBoroughName": "MANHATTAN",
        "firstStreetCode": "13577001010",
        "firstStreetNameNormalized": "WEST  100 STREET",
        "geosupportFunctionCode": "AP",
        "geosupportReturnCode": "00",
        "gi5DigitStreetCode1": "35770",
        "giBoroughCode1": "1",
        "giBuildingIdentificationNumber1": "1057093",
        "giDcpPreferredLgc1": "01",
        "giHighHouseNumber1": "314",
        "giLowHouseNumber1": "314",
        "giSideOfStreetIndicator1": "L",
        "giStreetCode1": "13577001",
        "highBblBoroughCode": "1",
        "highBblOfThisBuildingsCondominiumUnits": "1018881233",
        "highBblTaxBlock": "01888",
        "highBblTaxLot": "1233",
        "houseNumber": "314",
        "houseNumberIn": "314",
        "houseNumberSortFormat": "000314000AA",
        "latitude": "40.798118",
        "longitude": "-73.972323",
        "lowBblBoroughCode": "1",
        "lowBblOfThisBuildingsCondominiumUnits": "1018881201",
        "lowBblTaxBlock": "01888",
        "lowBblTaxLot": "1201",
        "lowHouseNumberOfDefiningAddressRange": "000314000AA",
        "numberOfEntriesInListOfGeographicIdentifiers": "0001",
        "numberOfExistingStructuresOnLot": "0001",
        "streetName1In": "W 100 ST",
        "workAreaFormatIndicatorIn": "C",
        "xCoordinate": "0991913",
        "yCoordinate": "0230054"
    }
}

3.3. BBL

Path: /v2/bbl

Parameters:

Table 8. /bbl arguments

Parameter Name

Required/Optional

Comments

borough

required

Valid values defined in Borough.

block

required

Tax block. Zero padding is not required.

lot

required

Tax lot. Zero padding is not required.

Example Requests:

Request:

/geoclient/v2/bbl?borough=manhattan&block=67&lot=1
Show JSON
{
    "bbl": {
        "bbl": "1000670001",
        "bblBoroughCode": "1",
        "bblBoroughCodeIn": "1",
        "bblTaxBlock": "00067",
        "bblTaxBlockIn": "67",
        "bblTaxLot": "0001",
        "bblTaxLotIn": "1",
        "buildingIdentificationNumber": "1079043",
        "businessImprovementDistrict": "113140",
        "condominiumBillingBbl": "0000000000",
        "cooperativeIdNumber": "0000",
        "cornerCode": "CR",
        "dcpCommercialStudyArea": "11004",
        "firstBoroughName": "MANHATTAN",
        "geosupportFunctionCode": "BL",
        "geosupportReturnCode": "00",
        "gi5DigitStreetCode1": "24050",
        "gi5DigitStreetCode2": "25630",
        "gi5DigitStreetCode3": "45440",
        "gi5DigitStreetCode4": "45440",
        "giBoroughCode1": "1",
        "giBoroughCode2": "1",
        "giBoroughCode3": "1",
        "giBoroughCode4": "1",
        "giBuildingIdentificationNumber1": "1079043",
        "giBuildingIdentificationNumber2": "1079043",
        "giBuildingIdentificationNumber3": "1079043",
        "giBuildingIdentificationNumber4": "1079043",
        "giDcpPreferredLgc1": "01",
        "giDcpPreferredLgc2": "01",
        "giDcpPreferredLgc3": "01",
        "giDcpPreferredLgc4": "01",
        "giHighHouseNumber1": "68",
        "giHighHouseNumber2": "65",
        "giHighHouseNumber3": "99",
        "giHighHouseNumber4": "105",
        "giLowHouseNumber1": "50",
        "giLowHouseNumber2": "41",
        "giLowHouseNumber3": "85",
        "giLowHouseNumber4": "101",
        "giSideOfStreetIndicator1": "R",
        "giSideOfStreetIndicator2": "L",
        "giSideOfStreetIndicator3": "L",
        "giSideOfStreetIndicator4": "L",
        "giStreetCode1": "12405001",
        "giStreetCode2": "12563001",
        "giStreetCode3": "14544001",
        "giStreetCode4": "14544001",
        "giStreetName1": "JOHN STREET",
        "giStreetName2": "MAIDEN LANE",
        "giStreetName3": "WILLIAM STREET",
        "giStreetName4": "WILLIAM STREET",
        "highBblOfThisBuildingsCondominiumUnits": "1000670001",
        "internalLabelXCoordinate": "0982037",
        "internalLabelYCoordinate": "0197460",
        "latitudeInternalLabel": 40.708659,
        "longitudeInternalLabel": -74.007982,
        "lowBblOfThisBuildingsCondominiumUnits": "1000670001",
        "lowHouseNumberOfDefiningAddressRange": "000050000AA",
        "modeSwitchIn": "X",
        "numberOfEntriesInListOfGeographicIdentifiers": "0004",
        "numberOfExistingStructuresOnLot": "0001",
        "numberOfStreetFrontagesOfLot": "03",
        "returnCode1a": "00",
        "rpadBuildingClassificationCode": "O4",
        "rpadSelfCheckCodeForBbl": "7",
        "sanbornBoroughCode": "1",
        "sanbornPageNumber": "011",
        "sanbornVolumeNumber": "01",
        "sanbornVolumeNumberSuffix": "S",
        "taxMapNumberSectionAndVolume": "10102",
        "workAreaFormatIndicatorIn": "C"
    }
}

3.4. BIN

Path: /v2/bin

Parameters:

Table 9. /bin arguments
Parameter Name Required/Optional Comments

bin

required

Building identification number.

Example Requests:

Request:

/geoclient/v2/bin?bin=1079043
Show JSON
{
    "bin": {
        "bbl": "1000670001",
        "bblBoroughCode": "1",
        "bblTaxBlock": "00067",
        "bblTaxLot": "0001",
        "buildingIdentificationNumber": "1079043",
        "buildingIdentificationNumberIn": "1079043",
        "businessImprovementDistrict": "113140",
        "condominiumBillingBbl": "0000000000",
        "cooperativeIdNumber": "0000",
        "cornerCode": "CR",
        "dcpCommercialStudyArea": "11004",
        "firstBoroughName": "MANHATTAN",
        "geosupportFunctionCode": "BN",
        "geosupportReturnCode": "00",
        "gi5DigitStreetCode1": "24050",
        "gi5DigitStreetCode2": "25630",
        "gi5DigitStreetCode3": "45440",
        "gi5DigitStreetCode4": "45440",
        "giBoroughCode1": "1",
        "giBoroughCode2": "1",
        "giBoroughCode3": "1",
        "giBoroughCode4": "1",
        "giBuildingIdentificationNumber1": "1079043",
        "giBuildingIdentificationNumber2": "1079043",
        "giBuildingIdentificationNumber3": "1079043",
        "giBuildingIdentificationNumber4": "1079043",
        "giDcpPreferredLgc1": "01",
        "giDcpPreferredLgc2": "01",
        "giDcpPreferredLgc3": "01",
        "giDcpPreferredLgc4": "01",
        "giHighHouseNumber1": "68",
        "giHighHouseNumber2": "65",
        "giHighHouseNumber3": "99",
        "giHighHouseNumber4": "105",
        "giLowHouseNumber1": "50",
        "giLowHouseNumber2": "41",
        "giLowHouseNumber3": "85",
        "giLowHouseNumber4": "101",
        "giSideOfStreetIndicator1": "R",
        "giSideOfStreetIndicator2": "L",
        "giSideOfStreetIndicator3": "L",
        "giSideOfStreetIndicator4": "L",
        "giStreetCode1": "12405001",
        "giStreetCode2": "12563001",
        "giStreetCode3": "14544001",
        "giStreetCode4": "14544001",
        "giStreetName1": "JOHN STREET",
        "giStreetName2": "MAIDEN LANE",
        "giStreetName3": "WILLIAM STREET",
        "giStreetName4": "WILLIAM STREET",
        "highBblOfThisBuildingsCondominiumUnits": "1000670001",
        "internalLabelXCoordinate": "0982037",
        "internalLabelYCoordinate": "0197460",
        "latitudeInternalLabel": 40.708659,
        "longitudeInternalLabel": -74.007982,
        "lowBblOfThisBuildingsCondominiumUnits": "1000670001",
        "lowHouseNumberOfDefiningAddressRange": "000050000AA",
        "modeSwitchIn": "X",
        "numberOfEntriesInListOfGeographicIdentifiers": "0004",
        "numberOfExistingStructuresOnLot": "0001",
        "numberOfStreetFrontagesOfLot": "03",
        "returnCode1a": "00",
        "rpadBuildingClassificationCode": "O4",
        "rpadSelfCheckCodeForBbl": "7",
        "sanbornBoroughCode": "1",
        "sanbornPageNumber": "011",
        "sanbornVolumeNumber": "01",
        "sanbornVolumeNumberSuffix": "S",
        "taxMapNumberSectionAndVolume": "10102",
        "workAreaFormatIndicatorIn": "C"
    }
}

3.5. Blockface

Path: /v2/blockface

Parameters:

Table 10. /blockface arguments
Parameter Name Required/Optional Comments

onStreet

required

Name of the street between the two cross streets.

crossStreetOne

required

First cross street of blockface.

crossStreetTwo

required

Second cross street of blockface.

borough

required

Borough of onStreet. Valid values defined in Borough.

boroughCrossStreetOne

optional

Borough of first cross street. Defaults to value of borough parameter if not supplied.

boroughCrossStreetTwo

optional

Borough of second cross street. Defaults to value of borough parameter if not supplied.

compassDirection

optional

Used to request information about only one side of the street. Valid values are: N, S, E, or W.

Example Requests:

Request:

/geoclient/v2/blockface?onStreet=broadway&crossStreetOne=w%20100%20st&crossStreetTwo=w%20101%st&borough=manhattan
Show JSON
{
    "blockface": {
        "boroughCode1In": "1",
        "coincidentSegmentCount": "1",
        "crossStreetNamesFlagIn": "E",
        "dcpPreferredLgcForStreet1": "01",
        "dcpPreferredLgcForStreet2": "01",
        "dcpPreferredLgcForStreet3": "01",
        "dotStreetLightContractorArea": "1",
        "firstBoroughName": "MANHATTAN",
        "firstStreetCode": "11361001010",
        "firstStreetNameNormalized": "BROADWAY",
        "fromLgc1": "01",
        "fromNode": "0023425",
        "fromXCoordinate": "0992580",
        "fromYCoordinate": "0229726",
        "genericId": "0002439",
        "geosupportFunctionCode": "3",
        "geosupportReturnCode": "00",
        "highCrossStreetB5SC1": "135790",
        "latitudeOfFromIntersection": "40.797217",
        "latitudeOfToIntersection": "40.797837",
        "leftSegment1990CensusTract": " 187  ",
        "leftSegment2000CensusBlock": "4001",
        "leftSegment2000CensusTract": " 187  ",
        "leftSegment2010CensusBlock": "3001",
        "leftSegment2010CensusTract": " 187  ",
        "leftSegment2020CensusBlock": "3001",
        "leftSegment2020CensusTrack": " 187  ",
        "leftSegment2020CensusTract": " 187  ",
        "leftSegmentAssemblyDistrict": "69",
        "leftSegmentBlockfaceId": "1322605056",
        "leftSegmentBoroughCode": "1",
        "leftSegmentCdta2020": "MN07",
        "leftSegmentCommunityDistrict": "107",
        "leftSegmentCommunityDistrictBoroughCode": "1",
        "leftSegmentCommunityDistrictNumber": "07",
        "leftSegmentCommunitySchoolDistrict": "03",
        "leftSegmentDynamicBlock": "401",
        "leftSegmentElectionDistrict": "044",
        "leftSegmentFireBattalion": "11",
        "leftSegmentFireCompanyNumber": "076",
        "leftSegmentFireCompanyType": "E",
        "leftSegmentFireDivision": "03",
        "leftSegmentHealthArea": "3110",
        "leftSegmentHealthCenterDistrict": "16",
        "leftSegmentHighHouseNumber": "0002657",
        "leftSegmentInterimAssistanceEligibilityIndicator": "I",
        "leftSegmentLowHouseNumber": "0002641",
        "leftSegmentNta": "MN12",
        "leftSegmentNta2020": "MN0703",
        "leftSegmentPolicePatrolBorough": "MN",
        "leftSegmentPolicePatrolBoroughCommand": "2",
        "leftSegmentPolicePrecinct": "024",
        "leftSegmentPoliceSector": "24A",
        "leftSegmentPumaCode": "03806",
        "leftSegmentZipCode": "10025",
        "legacyId": "0037356",
        "lengthOfSegmentInFeet": "00260",
        "lgc1": "01",
        "lionBoroughCode": "1",
        "lionFaceCode": "0755",
        "lionKey": "1075505240",
        "lionSequenceNumber": "05240",
        "longitudeOfFromIntersection": "-73.969914",
        "longitudeOfToIntersection": "-73.969455",
        "lowCrossStreetB5SC1": "135770",
        "modeSwitchIn": "X",
        "numberOfCrossStreetB5SCsHighAddressEnd": "1",
        "numberOfCrossStreetB5SCsLowAddressEnd": "1",
        "numberOfParkingLanesOnStreet": "2",
        "numberOfStreetCodesAndNamesInList": "02",
        "numberOfTotalLanesOnStreet": "8",
        "numberOfTravelLanesOnStreet": "6",
        "rightSegment1990CensusTract": " 187  ",
        "rightSegment2000CensusBlock": "1001",
        "rightSegment2000CensusTract": " 187  ",
        "rightSegment2010CensusBlock": "5001",
        "rightSegment2010CensusTract": " 187  ",
        "rightSegment2020CensusBlock": "5001",
        "rightSegment2020CensusTrack": " 187  ",
        "rightSegment2020CensusTract": " 187  ",
        "rightSegmentAssemblyDistrict": "69",
        "rightSegmentBlockfaceId": "1322607051",
        "rightSegmentBoroughCode": "1",
        "rightSegmentCdta2020": "MN07",
        "rightSegmentCommunityDistrict": "107",
        "rightSegmentCommunityDistrictBoroughCode": "1",
        "rightSegmentCommunityDistrictNumber": "07",
        "rightSegmentCommunitySchoolDistrict": "03",
        "rightSegmentDynamicBlock": "103",
        "rightSegmentElectionDistrict": "032",
        "rightSegmentFireBattalion": "11",
        "rightSegmentFireCompanyNumber": "076",
        "rightSegmentFireCompanyType": "E",
        "rightSegmentFireDivision": "03",
        "rightSegmentHealthArea": "3110",
        "rightSegmentHealthCenterDistrict": "16",
        "rightSegmentHighHouseNumber": "0002658",
        "rightSegmentInterimAssistanceEligibilityIndicator": "I",
        "rightSegmentLowHouseNumber": "0002638",
        "rightSegmentNta": "MN12",
        "rightSegmentNta2020": "MN0703",
        "rightSegmentPolicePatrolBorough": "MN",
        "rightSegmentPolicePatrolBoroughCommand": "2",
        "rightSegmentPolicePrecinct": "024",
        "rightSegmentPoliceSector": "24C",
        "rightSegmentPumaCode": "03806",
        "rightSegmentZipCode": "10025",
        "roadwayType": "1",
        "sanitationSnowPriorityCode": "C",
        "secondStreetCode": "13577001010",
        "secondStreetNameNormalized": "WEST  100 STREET",
        "segmentAzimuth": "060",
        "segmentIdentifier": "0037356",
        "segmentOrientation": "N",
        "segmentTypeCode": "G",
        "streetCode1": "13577001",
        "streetCode6": "13579001",
        "streetName1": "WEST  100 STREET",
        "streetName1In": "BROADWAY",
        "streetName2In": "W 100 ST",
        "streetName3In": "W 101 ST",
        "streetName6": "WEST  101 STREET",
        "streetStatus": "2",
        "thirdStreetCode": "13579001010",
        "thirdStreetNameNormalized": "WEST  101 STREET",
        "toLgc1": "01",
        "toNode": "0023427",
        "toXCoordinate": "0992707",
        "toYCoordinate": "0229952",
        "trafficDirection": "T",
        "workAreaFormatIndicatorIn": "C"
    }
}

3.6. Intersection

Path: /v2/blockface

Parameters:

Table 11. /intersection arguments
Parameter Name Required/Optional Comments

crossStreetOne

required

First cross street of the intersection.

crossStreetTwo

required

Second cross street of the intersection.

borough

required

Borough of first cross street or of both cross streets if no other borough parameter is supplied. Valid values defined in Borough.

boroughCrossStreetTwo

optional

Borough of second cross street. If not supplied, assumed to be same as borough parameter.

compassDirection

optional

Optional for most requests. Required only if the cross streets intersect more than once. Valid values are: N, S, E or W.

Example Requests:

Request:

/geoclient/v2/intersection?crossStreetOne=broadway&crossStreetOne=w%20100%20st&borough=manhattan
Show JSON
{
    "intersection": {
        "assemblyDistrict": "69",
        "atomicPolygon": "102",
        "boroughCode1In": "1",
        "cdta2020": "MN07",
        "censusBlock2020": "5001",
        "censusTract1990": " 187  ",
        "censusTract2000": " 187  ",
        "censusTract2010": " 187  ",
        "censusTract2020": " 187  ",
        "cityCouncilDistrict": "07",
        "civilCourtDistrict": "05",
        "communityDistrict": "107",
        "communityDistrictBoroughCode": "1",
        "communityDistrictNumber": "07",
        "communitySchoolDistrict": "03",
        "congressionalDistrict": "12",
        "crossStreetNamesFlagIn": "E",
        "dcpPreferredLgcForStreet1": "01",
        "dcpPreferredLgcForStreet2": "01",
        "dotStreetLightContractorArea": "1",
        "fireBattalion": "11",
        "fireCompanyNumber": "076",
        "fireCompanyType": "E",
        "fireDivision": "03",
        "firstBoroughName": "MANHATTAN",
        "firstStreetCode": "11361001010",
        "firstStreetNameNormalized": "BROADWAY",
        "geosupportFunctionCode": "2W",
        "geosupportReturnCode": "00",
        "healthArea": "3110",
        "healthCenterDistrict": "16",
        "instructionalRegion": "MN",
        "interimAssistanceEligibilityIndicator": "I",
        "intersectingStreet1": "113610",
        "intersectingStreet2": "135770",
        "latitude": 40.797217,
        "lgcListForStreet1": "01",
        "lgcListForStreet2": "01",
        "lionNodeNumber": "0023425",
        "listOfPairsOfLevelCodes": "**MM",
        "longitude": -73.969914,
        "nta2020": "MN0703",
        "numberOfIntersectingStreets": "2",
        "numberOfStreetCodesAndNamesInList": "02",
        "policePatrolBoroughCommand": "2",
        "policePrecinct": "024",
        "policeSector": "24C",
        "preferredLgcsForIntersectingStreets": "0101",
        "returnCode2w": "00",
        "sanbornBoroughCode1": "1",
        "sanbornPageNumber1": "036",
        "sanbornVolumeNumber1": "07",
        "sanbornVolumeNumberSuffix1": "S",
        "sanitationCollectionSchedulingSectionAndSubsection": "5B",
        "sanitationDistrict": "107",
        "sanitationSection": "161",
        "secondStreetCode": "13577001010",
        "secondStreetNameNormalized": "WEST  100 STREET",
        "stateSenatorialDistrict": "47",
        "streetCode1": "11361001",
        "streetCode2": "13577001",
        "streetName1": "BROADWAY",
        "streetName1In": "BROADWAY",
        "streetName2": "WEST  100 STREET",
        "streetName2In": "W 100 ST",
        "trueReplicationCounter": "01",
        "workAreaFormatIndicatorIn": "C",
        "xCoordinate": "0992580",
        "yCoordinate": "0229726",
        "zipCode": "10025"
    }
}

3.7. Normalize

Path: /v2/normalize

Parameters:

Table 12. /normalize arguments
Parameter Name Required/Optional Comments

name

required

Street name to normalize. Note that no validation is done to verify if this is a valid NYC street.

length

optional

The length of the normalized street name that is returned. Valid values are from 4 through 32. If no parameter is given, defaults to 32.

format

optional

S for sort format or C for compact format. Defaults to sort format.

Example Requests:

Request:

/geoclient/v2/name?name=east%20158th%20Street
Show JSON
{
    "normalize": {
        "firstStreetNameNormalized": "EAST  158 STREET",
        "geosupportFunctionCode": "N*",
        "geosupportReturnCode": "00",
        "streetName1In": "EAST 158TH STREET",
        "streetNameNormalizationFormatFlagIn": "S",
        "streetNameNormalizationLengthLimitIn": "32",
        "workAreaFormatIndicatorIn": "C"
    }
}

3.8. Place

Path: /v2/place

Parameters:

Table 13. /place arguments
Parameter Name Required/Optional Comments

name

required

Well-known place name.

borough

required if zip is not given

Valid values defined in Borough.

zip

required if borough is not given

Standard USPS 5-digit zip code or zip+4 (see this article). Must be a valid zip code for an area within New York City limits.

Example Requests:

Request:

/geoclient/v2/place?name=george%20washington%20bridge&borough=manhattan
Show JSON
{
    "place": {
        "alleyCrossStreetsFlag": "X",
        "assemblyDistrict": "71",
        "bbl": "1021780003",
        "bblBoroughCode": "1",
        "bblTaxBlock": "02178",
        "bblTaxLot": "0003",
        "blockfaceId": "1322602164",
        "boardOfElectionsPreferredLgc": "1",
        "boePreferredStreetName": "GEORGE WASHINGTON BRIDGE",
        "boePreferredstreetCode": "19781001",
        "boroughCode1In": "1",
        "buildingIdentificationNumber": "1797010",
        "cdta2020": "MN12",
        "censusBlock2000": "9999",
        "censusBlock2010": "0001",
        "censusBlock2020": "0002",
        "censusTrack2020": " 275  ",
        "censusTract1990": " 313  ",
        "censusTract2000": " 313  ",
        "censusTract2010": " 255  ",
        "censusTract2020": " 275  ",
        "cityCouncilDistrict": "10",
        "civilCourtDistrict": "00",
        "coincidentSegmentCount": "1",
        "communityDistrict": "112",
        "communityDistrictBoroughCode": "1",
        "communityDistrictNumber": "12",
        "condominiumBillingBbl": "0000000000",
        "congressionalDistrict": "13",
        "cooperativeIdNumber": "0000",
        "crossStreetNamesFlagIn": "E",
        "dcpPreferredLgc": "01",
        "dcpZoningMap": "3A",
        "dotStreetLightContractorArea": "N",
        "dynamicBlock": "013",
        "electionDistrict": "067",
        "firstBoroughName": "MANHATTAN",
        "firstStreetCode": "19781001030",
        "firstStreetNameNormalized": "GEORGE WASHINGTON BRIDGE",
        "fromActualSegmentNodeId": "9013111",
        "fromLionNodeId": "0024375",
        "fromPreferredLgcsFirstSetOf5": "18",
        "genericId": "0067182",
        "geosupportFunctionCode": "1B",
        "geosupportReturnCode": "00",
        "geosupportReturnCode2": "00",
        "gi5DigitStreetCode1": "97810",
        "gi5DigitStreetCode2": "37270",
        "gi5DigitStreetCode3": "29690",
        "giBoroughCode1": "1",
        "giBoroughCode2": "1",
        "giBoroughCode3": "1",
        "giBuildingIdentificationNumber1": "1797010",
        "giBuildingIdentificationNumber2": "1000000",
        "giBuildingIdentificationNumber3": "1000000",
        "giDcpPreferredLgc1": "01",
        "giDcpPreferredLgc2": "01",
        "giDcpPreferredLgc3": "01",
        "giGeographicIdentifier1": "T",
        "giGeographicIdentifier2": "F",
        "giGeographicIdentifier3": "F",
        "giSideOfStreetIndicator1": "L",
        "giStreetCode1": "19781001",
        "giStreetCode2": "13727001",
        "giStreetCode3": "12969001",
        "giStreetName1": "GEORGE WASHINGTON BRIDGE",
        "giStreetName2": "WEST  176 STREET",
        "giStreetName3": "RIVERSIDE DRIVE",
        "healthArea": "8700",
        "healthCenterDistrict": "17",
        "highBblOfThisBuildingsCondominiumUnits": "1021780003",
        "highCrossStreetB5SC1": "111450",
        "highCrossStreetB5SC2": "100107",
        "highCrossStreetCode1": "11145005",
        "highCrossStreetCode2": "10010701",
        "highCrossStreetName1": "NY-NJ BOUNDARY",
        "highCrossStreetName2": "CITY LIMIT",
        "highHouseNumberOfBlockfaceSortFormat": "000000000AA",
        "hurricaneEvacuationZone": "0",
        "individualSegmentLength": "01440",
        "instructionalRegion": "MN",
        "interimAssistanceEligibilityIndicator": "I",
        "internalLabelXCoordinate": "1000116",
        "internalLabelYCoordinate": "0250452",
        "latitude": 40.851279,
        "latitudeInternalLabel": 40.854094,
        "legacySegmentId": "0039008",
        "lionBoroughCode": "1",
        "lionBoroughCodeForVanityAddress": "1",
        "lionFaceCode": "2586",
        "lionFaceCodeForVanityAddress": "2586",
        "lionKey": "1258600045",
        "lionKeyForVanityAddress": "1258600045",
        "lionSequenceNumber": "00045",
        "lionSequenceNumberForVanityAddress": "00045",
        "listOf4Lgcs": "01",
        "longitude": -73.950541,
        "longitudeInternalLabel": -73.942647,
        "lowBblOfThisBuildingsCondominiumUnits": "1021780003",
        "lowCrossStreetB5SC1": "130497",
        "lowCrossStreetCode1": "13049718",
        "lowCrossStreetName1": "HUDSON RIVER SHORELINE",
        "lowHouseNumberOfBlockfaceSortFormat": "000000000AA",
        "lowHouseNumberOfDefiningAddressRange": "000001000AA",
        "noCrossStreetCalculationFlag": "Y",
        "nta": "MN35",
        "nta2020": "MN1202",
        "numberOfCrossStreetB5SCsHighAddressEnd": "2",
        "numberOfCrossStreetB5SCsLowAddressEnd": "1",
        "numberOfCrossStreetsHighAddressEnd": "2",
        "numberOfCrossStreetsLowAddressEnd": "1",
        "numberOfEntriesInListOfGeographicIdentifiers": "0003",
        "numberOfExistingStructuresOnLot": "0001",
        "numberOfStreetFrontagesOfLot": "03",
        "numberOfTotalLanesOnTheStreet": "8",
        "numberOfTravelLanesOnTheStreet": "8",
        "policePatrolBoroughCommand": "2",
        "policePrecinct": "033",
        "policeSector": "33D",
        "pumaCode": "03801",
        "returnCode1a": "00",
        "returnCode1e": "00",
        "roadwayType": "3",
        "rpadBuildingClassificationCode": "V1",
        "rpadSelfCheckCodeForBbl": "6",
        "sanbornBoroughCode": "1",
        "sanbornPageNumber": "013",
        "sanbornVolumeNumber": "12",
        "sanitationCommercialWasteZone": "MN7",
        "sanitationDistrict": "112",
        "sanitationSection": "12",
        "sanitationSnowPriorityCode": "V",
        "segmentAzimuth": "165",
        "segmentIdentifier": "9014075",
        "segmentLengthInFeet": "01733",
        "segmentOrientation": "3",
        "segmentTypeCode": "G",
        "sideOfStreetIndicator": "L",
        "sideOfStreetOfVanityAddress": "L",
        "specialAddressGeneratedRecordFlag": "N",
        "splitLowHouseNumber": "000001000AA",
        "stateSenatorialDistrict": "31",
        "streetName1In": "GEORGE WASHINGTON BRIDGE",
        "streetStatus": "2",
        "taxMapNumberSectionAndVolume": "10803",
        "toActualSegmentNodeId": "0093956",
        "toLionNodeId": "0093956",
        "toPreferredLgcsFirstSetOf5": "0501",
        "trafficDirection": "T",
        "underlyingHnsOnTrueStreet": "000000000AA",
        "underlyingStreetCode": "19781001",
        "uspsPreferredCityName": "NEW YORK",
        "workAreaFormatIndicatorIn": "C",
        "xCoordActualSegmentHighAddressEnd": "0997255",
        "xCoordActualSegmentLowAddressEnd": "0998649",
        "xCoordinate": "0997933",
        "xCoordinateHighAddressEnd": "0997255",
        "xCoordinateLowAddressEnd": "0998933",
        "xCoordinateOfCenterofCurvature": "0000000",
        "yCoordActualSegmentHighAddressEnd": "0249587",
        "yCoordActualSegmentLowAddressEnd": "0249227",
        "yCoordinate": "0249425",
        "yCoordinateHighAddressEnd": "0249587",
        "yCoordinateLowAddressEnd": "0249152",
        "yCoordinateOfCenterofCurvature": "0000000",
        "zipCode": "10033"
    }
}
Table 14. /place arguments

Parameter Name

Required/Optional

Comments

The /search endpoint provides a way to search for an address, BBL, BIN, blockface, or place using a single unparsed location string. Assuming that the Geoclient parser can guess the location type requested and the given single-field input parameter contains contains enough information to generate a successful Geosupport call, the service will return one or more sets of geocodes corresponding to the type of request that was made.

The single-field search will attempt to recognize the type of request being made using the following (simplified) parsing strategies which are listed in the order they are executed:

  1. A ten-digit number where the first digit is 1, 2, 3, 4 or 5 is recognized as a BBL request:

    1000670001
  2. A seven-digit number where the first digit is 1, 2, 3, 4 or 5 is recognized as a BIN request:

    1079043
  3. If the input string ends with a United States-related country identifier it is recognized and removed and discarded:

    314 W 100 ST, NY, NY 10025 [USA]
  4. If the input string ends with a five or seven-digit zipcode it is removed and kept as a <ZIP> token:

    314 W 100 ST, NY, NY [10025]
  5. If the input string ends with a valid two-character U.S. state abreviation it is recognized and removed:

    314 W 100 ST, NY, [NY]
Note
Input ending in only a single instance of NY or New York (case-insensitive) is treated as a city name alias for Manhattan and not the state of New York.
  1. If the input string ends with a known NYC city name it is removed and kept as a <CITY_NAME> token:

    93-02 69th Ave, [Forest Hills]
  2. If the input string ends with a known borough name or abreviation it is removed and kept as a <BOROUGH_NAME> token:

    80 Monroe Ave [SI]
  3. A BLOCKFACE request is identified using the pattern <ON_STREET> between <CROSS_STREET_ONE> and <CROSS_STREET_TWO>:

    [Broadway] between [W 100 St] and [W 101 St]
  4. An INTERSECTION request is identified using the pattern <CROSS_STREET_ONE> and <CROSS_STREET_TWO>:

    [Broadway] and [W 100 St]
  5. If the input string starts with a known house number format, it is recognized and kept as <BASIC_HOUSE_NUMBER> and (optionally) <HOUSE_NUMBER_SUFFIX> token(s):

    [93-02] 69th Ave
  6. Any remaining input is treated as an input street. If a <BASIC_HOUSE_NUMBER> token has been parsed, the input is recognized as an ADDRESS request, otherwise it is defaulted to a PLACE request

All matching is case-insensitive. Leading/trailing whitespace and any punctuation characters are ignored.

After the input has been parsed into tokens and the request type has been determined, the service resolves the BOROUGH_NAME and/or CITY_NAME token(s) into a New York City borough code (1=Manhattan, 2=Bronx, 3=Brooklyn, 4=Queens, 5=Staten Island).

If a valid borough code has been resolved, a single request is made to Geosupport using the specified borough code. The request is assigned a "level" of zero.

If a valid borough code cannot be derived (either because no borough was provided or the provided borough/city name is not recognized), five requests are automatically submitted - one for each borough. Each request is assigned a "level" of one.

The Geoclient service uses the concept of search levels to classify the degree to which any user input has been modified by the program before making the request to Geosupport. Roughly speaking, each additional level indicates a round of sub-searches undertaken when the service does not find an exact match.

Path: /v2/search

Parameters:

Table 15. /search arguments
Parameter Name Required/Optional Comments

input

required

Unparsed location input.

exactMatchForSingleSuccess

optional

Whether a search returning only one possible successfully geocoded location is considered an exact match. Defaults to false.

exactMatchMaxLevel

optional

The maximum number of sub-search levels to perform if Geosupport rejects the input but suggests alternative street names, etc. Defaults to 3. Maximum is allowable value is 6.

returnPolicy

optional

Whether to return information on the search policy used to perform the search. Defaults to false.

returnPossiblesWithExact

optional

Whether to also return successfully geocoded possible matches when available in addition to the exact match. Defaults to false.

returnRejections

optional

Whether to return rejected response data from Geosupport. Defaults to false.

returnTokens

optional

Whether to return the parsed input tokens recognized by the parser. Defaults to false.

similarNamesDistance

optional

Maximum allowable Levenshtein distance between user input and a similar name suggestion from Geosupport. Defaults to 8. A higher number will allow more "guesses" to be made about an unrecognized street name.

Example Requests:

Request:

/geoclient/v2/search?input=314%20w%20100%20st%20manhattan
Show JSON
{
    "id": "a8f35a4a43d0-11-1714162066783",
    "status": "OK",
    "input": "314 w 100 st manhattan",
    "results": [
        {
            "level": "0",
            "status": "EXACT_MATCH",
            "request": "address [houseNumber=314, street=w 100 st, borough=MANHATTAN, zip=null]",
            "response": {
                "alleyCrossStreetsFlag": "X",
                "assemblyDistrict": "69",
                "bbl": "1018887502",
                "bblBoroughCode": "1",
                "bblTaxBlock": "01888",
                "bblTaxLot": "7502",
                "blockfaceId": "1322604631",
                "boardOfElectionsPreferredLgc": "1",
                "boePreferredStreetName": "WEST  100 STREET",
                "boePreferredstreetCode": "13577001",
                "boroughCode1In": "1",
                "buildingIdentificationNumber": "1057093",
                "cdta2020": "MN07",
                "censusBlock2000": "6000",
                "censusBlock2010": "2000",
                "censusBlock2020": "2000",
                "censusTrack2020": " 187  ",
                "censusTract1990": " 187  ",
                "censusTract2000": " 187  ",
                "censusTract2010": " 187  ",
                "censusTract2020": " 187  ",
                "cityCouncilDistrict": "07",
                "civilCourtDistrict": "05",
                "coincidentSegmentCount": "1",
                "communityDistrict": "107",
                "communityDistrictBoroughCode": "1",
                "communityDistrictNumber": "07",
                "communitySchoolDistrict": "03",
                "condominiumBillingBbl": "1018887502",
                "condominiumFlag": "C",
                "congressionalDistrict": "12",
                "cooperativeIdNumber": "0000",
                "crossStreetNamesFlagIn": "E",
                "dcpPreferredLgc": "01",
                "dcpZoningMap": "5D",
                "dofCondominiumIdentificationNumber": "1981",
                "dotStreetLightContractorArea": "1",
                "dynamicBlock": "601",
                "electionDistrict": "045",
                "fireBattalion": "11",
                "fireCompanyNumber": "022",
                "fireCompanyType": "L",
                "fireDivision": "03",
                "firstBoroughName": "MANHATTAN",
                "firstStreetCode": "13577001010",
                "firstStreetNameNormalized": "WEST  100 STREET",
                "fromActualSegmentNodeId": "9051124",
                "fromLionNodeId": "0023422",
                "fromPreferredLgcsFirstSetOf5": "01",
                "genericId": "0167324",
                "geosupportFunctionCode": "1B",
                "geosupportReturnCode": "00",
                "geosupportReturnCode2": "00",
                "gi5DigitStreetCode1": "35770",
                "giBoroughCode1": "1",
                "giBuildingIdentificationNumber1": "1057093",
                "giDcpPreferredLgc1": "01",
                "giHighHouseNumber1": "316",
                "giLowHouseNumber1": "314",
                "giSideOfStreetIndicator1": "L",
                "giStreetCode1": "13577001",
                "giStreetName1": "WEST  100 STREET",
                "healthArea": "3110",
                "healthCenterDistrict": "16",
                "highBblOfThisBuildingsCondominiumUnits": "1018881233",
                "highCrossStreetB5SC1": "129690",
                "highCrossStreetCode1": "12969001",
                "highCrossStreetName1": "RIVERSIDE DRIVE",
                "highHouseNumberOfBlockfaceSortFormat": "000398000AA",
                "houseNumber": "314",
                "houseNumberIn": "314",
                "houseNumberSortFormat": "000314000AA",
                "hurricaneEvacuationZone": "X",
                "individualSegmentLength": "00118",
                "instructionalRegion": "MN",
                "interimAssistanceEligibilityIndicator": "I",
                "internalLabelXCoordinate": "0991892",
                "internalLabelYCoordinate": "0230017",
                "latitude": 40.798178,
                "latitudeInternalLabel": 40.798017,
                "legacySegmentId": "0037349",
                "lionBoroughCode": "1",
                "lionBoroughCodeForVanityAddress": "1",
                "lionFaceCode": "5345",
                "lionFaceCodeForVanityAddress": "5345",
                "lionKey": "1534500065",
                "lionKeyForVanityAddress": "1534500065",
                "lionSequenceNumber": "00065",
                "lionSequenceNumberForVanityAddress": "00065",
                "listOf4Lgcs": "01",
                "longitude": -73.972225,
                "longitudeInternalLabel": -73.972399,
                "lowBblOfThisBuildingsCondominiumUnits": "1018881201",
                "lowCrossStreetB5SC1": "144990",
                "lowCrossStreetCode1": "14499001",
                "lowCrossStreetName1": "WEST END AVENUE",
                "lowHouseNumberOfBlockfaceSortFormat": "000300000AA",
                "lowHouseNumberOfDefiningAddressRange": "000314000AA",
                "noCrossStreetCalculationFlag": "Y",
                "nta": "MN12",
                "nta2020": "MN0703",
                "numberOfCrossStreetB5SCsHighAddressEnd": "1",
                "numberOfCrossStreetB5SCsLowAddressEnd": "1",
                "numberOfCrossStreetsHighAddressEnd": "1",
                "numberOfCrossStreetsLowAddressEnd": "1",
                "numberOfEntriesInListOfGeographicIdentifiers": "0001",
                "numberOfExistingStructuresOnLot": "0001",
                "numberOfParkingLanesOnTheStreet": "2",
                "numberOfStreetFrontagesOfLot": "01",
                "numberOfTotalLanesOnTheStreet": "3",
                "numberOfTravelLanesOnTheStreet": "1",
                "physicalId": "0181278",
                "policePatrolBoroughCommand": "2",
                "policePrecinct": "024",
                "policeSector": "24A",
                "pumaCode": "03806",
                "returnCode1a": "00",
                "returnCode1e": "00",
                "roadwayType": "1",
                "rpadBuildingClassificationCode": "R4",
                "rpadSelfCheckCodeForBbl": "5",
                "sanbornBoroughCode": "1",
                "sanbornPageNumber": "034",
                "sanbornVolumeNumber": "07",
                "sanbornVolumeNumberSuffix": "S",
                "sanitationBulkPickupSchedule": "ETHS",
                "sanitationCollectionSchedulingSectionAndSubsection": "5R",
                "sanitationCommercialWasteZone": "MN5",
                "sanitationDistrict": "107",
                "sanitationRecyclingCollectionSchedule": "ET",
                "sanitationRegularCollectionSchedule": "TTHS",
                "sanitationSection": "075",
                "sanitationSnowPriorityCode": "H",
                "segmentAzimuth": "151",
                "segmentIdentifier": "0310083",
                "segmentLengthInFeet": "00574",
                "segmentOrientation": "W",
                "segmentTypeCode": "U",
                "selfCheckCodeOfBillingBbl": "5",
                "sideOfStreetIndicator": "L",
                "sideOfStreetOfVanityAddress": "L",
                "speedLimit": "25",
                "splitLowHouseNumber": "000314000AA",
                "stateSenatorialDistrict": "47",
                "streetName1In": "W 100 ST",
                "streetStatus": "2",
                "streetWidth": "30",
                "streetWidthMaximum": "30",
                "taxMapNumberSectionAndVolume": "10703",
                "toActualSegmentNodeId": "9051125",
                "toLionNodeId": "0023852",
                "toPreferredLgcsFirstSetOf5": "01",
                "trafficDirection": "A",
                "underlyingStreetCode": "13577001",
                "uspsPreferredCityName": "NEW YORK",
                "workAreaFormatIndicatorIn": "C",
                "xCoordActualSegmentHighAddressEnd": "0991854",
                "xCoordActualSegmentLowAddressEnd": "0991957",
                "xCoordinate": "0991940",
                "xCoordinateHighAddressEnd": "0991683",
                "xCoordinateLowAddressEnd": "0992186",
                "xCoordinateOfCenterofCurvature": "0000000",
                "yCoordActualSegmentHighAddressEnd": "0230127",
                "yCoordActualSegmentLowAddressEnd": "0230070",
                "yCoordinate": "0230076",
                "yCoordinateHighAddressEnd": "0230221",
                "yCoordinateLowAddressEnd": "0229944",
                "yCoordinateOfCenterofCurvature": "0000000",
                "zipCode": "10025"
            }
        }
    ],
    "parseTree": null,
    "policy": null
}

3.10. Street Code

Path: /v2/streetcode

Parameters:

Table 16. /streetcode arguments
Parameter Name Required/Optional Comments

streetCode

required

B5SC, B7SC, or B10SC street code.

streetCodeTwo

optional

B5SC, B7SC, or B10SC street code.

streetCodeThree

optional

B5SC, B7SC, or B10SC street code.

length

optional

The length of the normalized street name that is returned. Valid values are from 4 through 32. If no parameter is given, defaults to 32.

format

optional

S for sort format or C for compact format. Defaults to sort format.

Example Requests:

Request:

/geoclient/v2/streetcode?streetCode=11061004010

Response:

Show JSON
{
    "streetcode": {
        "boroughCode1In": "1",
        "firstStreetCode": "11061004010",
        "firstStreetNameNormalized": "7 AVENUE",
        "geosupportFunctionCode": "DG",
        "geosupportReturnCode": "00",
        "streetCode1In": "1061004",
        "streetNameNormalizationFormatFlagIn": "S",
        "streetNameNormalizationLengthLimitIn": "32",
        "workAreaFormatIndicatorIn": "C"
    }
}

3.11. Version

Path: /v2/version

Parameters:

The /version endpoint does not accept any parameters.

Example Requests:

Request:

/geoclient/v2/version

Response:

Show JSON
{
    "geoclientJniVersion": "2.0.1-beta",
    "geoclientVersion": "2.0.1-beta",
    "geoclientParserVersion": "2.0.1-beta",
    "geoclientServiceVersion": "2.0.1-beta",
    "geosupportVersion": {
        "dsNames": [
            "edequiv",
            "GRID1",
            "GRID2",
            "GRID3",
            "PAD",
            "san",
            "snd",
            "STRETCH",
            "thined",
            "GRID1R",
            "AUXSEG",
            "TPAD",
            "apequiv",
            "AP",
            "UPAD",
            "STAT",
            "STT1",
            "STT1A",
            "STT2",
            "STT3",
            "STT3S",
            "STTAP",
            "STTBL",
            "STTBN",
            "STTD",
            "snequiv"
        ],
        "geoFileInfo": [
            {
                "tag": "GEO",
                "date": "240418",
                "release": "2420",
                "recordCount": "00000001",
                "recordType": "0000",
                "formattedDate": "2024-04-18"
            },
            {
                "tag": "EDEQ",
                "date": "200221",
                "release": "20A",
                "recordCount": "00000001",
                "recordType": "0000",
                "formattedDate": "2020-02-21"
            },
            {
                "tag": "GRD1",
                "date": "240418",
                "release": "24B",
                "recordCount": "00233117",
                "recordType": "0000",
                "formattedDate": "2024-04-18"
            },
            {
                "tag": "GRD2",
                "date": "240418",
                "release": "24B",
                "recordCount": "00078713",
                "recordType": "0000",
                "formattedDate": "2024-04-18"
            },
            {
                "tag": "GRD3",
                "date": "240418",
                "release": "24B",
                "recordCount": "00241035",
                "recordType": "0000",
                "formattedDate": "2024-04-18"
            },
            {
                "tag": "PAD",
                "date": "240412",
                "release": "24B",
                "recordCount": "01288684",
                "recordType": "0000",
                "formattedDate": "2024-04-12"
            },
            {
                "tag": "SAN",
                "date": "230914",
                "release": "23C1",
                "recordCount": "00000750",
                "recordType": "0000",
                "formattedDate": "2023-09-14"
            },
            {
                "tag": "SND",
                "date": "240417",
                "release": "24B",
                "recordCount": "00115483",
                "recordType": "0000",
                "formattedDate": "2024-04-17"
            },
            {
                "tag": "STCH",
                "date": "240418",
                "release": "24B",
                "recordCount": "00030167",
                "recordType": "0000",
                "formattedDate": "2024-04-18"
            }
        ],
        "thinFileInfo": {
            "tag": "THIN",
            "date": "240308",
            "release": "24A1",
            "recordCount": "00004422",
            "recordTypes": [
                "0000",
                "0001",
                "0002"
            ],
            "fillerFields": null,
            "formattedDate": "2024-03-08"
        },
        "apFileInfo": {
            "tag": "AP",
            "date": "240405",
            "release": "24B",
            "recordCount": "00968574",
            "recordType": "0000",
            "formattedDate": "2024-04-05"
        },
        "apequivFileInfo": {
            "tag": "APEQ",
            "date": "240416",
            "release": "24B",
            "recordCount": "00000001",
            "recordType": "0000",
            "formattedDate": "2024-04-16"
        },
        "auxsegFileInfo": {
            "tag": "SAUX",
            "date": "240418",
            "release": "24B",
            "recordCount": "00040937",
            "recordType": "0000",
            "formattedDate": "2024-04-18"
        },
        "grid1RFileInfo": {
            "tag": "GR1R",
            "date": "240418",
            "release": "24B",
            "recordCount": "00233089",
            "recordType": "0000",
            "formattedDate": "2024-04-18"
        },
        "sneqFileInfo": {
            "tag": "SNEQ",
            "date": "240416",
            "release": "24B",
            "recordCount": "00000819",
            "recordType": "0000",
            "formattedDate": "2024-04-16"
        },
        "stat1AFileInfo": {
            "tag": "A***",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STT1",
            "formattedDate": "******"
        },
        "stat1FileInfo": {
            "tag": "****",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STT1",
            "formattedDate": "******"
        },
        "stat2FileInfo": {
            "tag": "****",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STT2",
            "formattedDate": "******"
        },
        "stat3FileInfo": {
            "tag": "****",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STT3",
            "formattedDate": "******"
        },
        "stat3SFileInfo": {
            "tag": "S***",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STT3",
            "formattedDate": "******"
        },
        "statAPFileInfo": {
            "tag": "P***",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STTA",
            "formattedDate": "******"
        },
        "statBLFileInfo": {
            "tag": "L***",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STTB",
            "formattedDate": "******"
        },
        "statBNFileInfo": {
            "tag": "N***",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STTB",
            "formattedDate": "******"
        },
        "statDFileInfo": {
            "tag": "****",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STTD",
            "formattedDate": "******"
        },
        "statFileInfo": {
            "tag": "****",
            "date": "******",
            "release": "****",
            "recordCount": "********",
            "recordType": "STAT",
            "formattedDate": "******"
        },
        "tpadFileInfo": {
            "tag": "TPAD",
            "date": "240412",
            "release": "24A",
            "recordCount": "00000000",
            "recordType": "0000",
            "formattedDate": "2024-04-12"
        },
        "upadFileInfo": {
            "tag": "UPAD",
            "date": "240412",
            "release": "24B",
            "recordCount": "00000001",
            "recordType": "0000",
            "formattedDate": "2024-04-12"
        },
        "geofilesDirectory": "/opt/geosupport/current/fls/",
        "version": "24.2",
        "release": "24B"
    },
    "accessMethod": "Local/JNI"
}

4. Geosupport Documentation

This section provides links to Department of City Planning’s documentation for Geosupport.


5. Development

This section documents building Geoclient from source, the project’s core architecture and several development use cases.


5.1. Core design

The geoclient-core subproject defines the API and implementation of the Java classes responsible for transforming the output of a Geosupport function call into runtime objects contains a structured representation of the data. Geosupport responses are either one or two large character buffers containing position-delimited values defined by the Geosupport API. In Java land, courtesy of the geoclient-jni subproject, these buffers are contained in java.nio.ByteBuffer instances.

It is the responsibility of the classes in the gov.nyc.doitt.gis.geoclient.function package to pluck out each attribute and place it in a java.util.Map<String, Object>. The geoclient.xml configuration file provides the name of the attribute used as the Map key and the start and end positions of the attribute’s location in the ByteBuffer.

This class diagram shows the composition of the core classes responsibile for this process:

Function API class diagram
Figure 2. The Function API core classes

This sequence diagram shows the call graph of these objects at runtime:

Function API sequence diagram
Figure 3. The call sequence for the Function API

5.2. Platforms

Linux x86_64

Runs on recent kernel versions with libc6. Lots of successful production experience with debian and RHEL-based distros.

Windows x86_64

Can run on Windows 10 or 11. Not recommended for production use.

5.3. Building from source

Building Geoclient from source is tricky because of the many combinations of platforms, runtimes, tools, and pre-existing Geosupport binary artifacts.

At this time, the New York City Department of City Planning only distributes binaries for Linux and Windows. The macOS platform is not supported.

If you have a choice, prefer building on Linux as more of the standard C/JNI conventions work as expected. It is possible to build and run Geoclient/Geosupport on Windows, but we highly recommend Linux for the best performance.

Finally, always use 64-bit versions of all software. 32-bit versions are not supported.

5.3.1. Requirements

  • 64-bit Geosupport

  • 64-bit JDK 17+ ("Full" JDK required. JRE by itself will not build)

  • Gradle 8.7+

  • 64-bit Linux or Windows

  • 64-bit native C and C++ compilers: gcc and g++

5.3.2. Gradle Build

Gradle build from bash
git clone https://github.com/mlipper/geoclient
cd geoclient
./gradlew build

5.4. Projects

.
`-- geoclient
    |-- buildSrc
    |-- ci
    |-- config
    |   `-- checkstyle
    |-- documentation
    |-- geoclient-core
    |-- geoclient-jni
    |-- geoclient-parser
    |-- geoclient-service
    |-- geoclient-test
    |-- geoclient-utils
    |   |-- cli
    |   `-- jni-test
    |-- gradle
    |-- images
    |-- manifests
    `-- src
        |-- scripts
        `-- spotless

5.4.1. geoclient-service

The geoclient-service project uses Spring Boot for dependency-injection and to minimize the need boiler-plate code and configuration. The geoclient-service/src/main/resources/application.yaml file is used to configure the runtime environment and properties for different profiles.

For complete documentation of Spring Boot and the functionality configured in application.yaml, see:

The default profile is specified first and active unless overridden. Optional profiles are demarcated by lines beginning with "--" and can add new functionality or override default properties.

Note
When using gradle to run the bootRun task provided by the spring-boot plugin, the following syntax is used to specify active profiles and/or override specific application properties managed by spring-boot.

For example,

./gradlew bootRun --args='--spring.profiles.active=bootRun,accesslog --server.tomcat.basedir=/var/log'
Warning
This profile should NOT be used in production environments because it specifies a permissive configuration of Spring Actuator.
Note
Although no longer required, the Java system property gc.jni.version can be provided on any command line. This sets the name of the subfolder in java.tmpdir where the native libraries in the geoclient-jni jar will be unpacked.

For example, with the Gradle bootRun task:

  ./gradlew -Dgc.jni.version=geoclient-jni-2 ...
Note
The following logging levels can be added to any profile, including the default, for logging specific functionality.
geoclient-jni: "DEBUG"

Native C runtime and JNI configuration at startup.

gov.nyc.doitt.gis.geoclient.config.xml: "DEBUG"

XML deserialization into WorkArea fields at startup.

gov.nyc.doitt.gis.geoclient.function.GeosupportFunction: "TRACE"

Raw character buffer values from geosupport requests/repsonses.

gov.nyc.doitt.gis.geoclient.service.invoker.GeosupportServiceImpl: "DEBUG"

Request/response HashMaps before/after geosupport call.

Note
The accesslog profile enables HTTP request logging from the embedded Tomcat Servlet container. By default the log is written to: /workspaces/tomcat/logs/access.log
<server.tomcat.basedir> = /workspaces/tomcat
<server.tomcat.accesslog.directory> = logs
<server.tomcat.suffix> = .log

The <basedir> property is relative to the system temp directory if not given as an absolute path. The <accesslog.directory> is always relative to <basedir>.

Properties can be overridden at invocation time:

--server.tomcat.basedir=...
--server.tomcat...etc.

If experiencing issues, insure the tomcat-access logging group is defined above and set to TRACE below. Also, try creating the target directory if it does not exist before starting the app.

management:
  endpoint:
    health:
      group:
        readiness:
          include: "readinessState"
        liveliness:
          etc...

5.5. Docker

This section explains two common ways to build and run geoclient using Docker. It is based on Dockerfile files in the <project root>/images directory:

  • build.Dockerfile which installs Geosupport, builds this project from source, and then runs geoclient-service.

  • run.Dockerfile which runs geoclient-service using an externally specified geoclient-service Jar file in the container where a configured Geosupport installation has been mounted on the file system using a Docker Volume.

5.5.1. Assumptions

  • All examples assume you have a local clone of the geoclient GitHub repository and are running commands from the root project directory.

    See Building Docker Images below for details.

  • Containers built from these images expect that Geosupport (GEOSUPPORT_BASE) is installed in /opt/geosupport at runtime.

  • These examples start containers in the foregroung with the -t switch. To run geoclient in the background, use the -d switch instead.

5.5.2. Requirements

  • The geoclient REST service (geoclient-service) requires a Geosupport installation to work.

  • The examples here require the Geosupport distribution packaged by the geosupport-docker project:

    • Compiling the geoclient-jni C code requires patched header files.

    • The Dockerfile examples rely on the additional management and installation features that geosupport-docker provides.

    • See below for more details about geosupport-docker.

NOTE: geoclient can use the official Linux distribution of Geosupport available from New York City’s Department of City Planning. However, additional installation and configuration steps are required.

5.5.3. Building a Docker image from source

The purpose of this example is to demonstrate how to build and run Geoclient in a Docker container as might be done as part of a Continuous Integration pipeline.

Note
See the <project root>/ci/Dockerfile file which this project uses for CI. It similar build.Dockerfile but adds some extra commands to aggregate test and coverage reports.

Start by cloning geoclient from GitHub and changing to the project’s root directory.

git clone https://github.com/mlipper/geoclient

Cloning into 'geoclient'...
remote: Enumerating objects: 11580, done.
remote: Counting objects: 100% (2578/2578), done.
remote: Compressing objects: 100% (904/904), done.
remote: Total 11580 (delta 1020), reused 2463 (delta 972), pack-reused 9002
Receiving objects: 100% (11580/11580), 10.27 MiB | 13.71 MiB/s, done.
Resolving deltas: 100% (4942/4942), done.

# Change to the root project directory.
cd ./geoclient

5.5.4. The build image

This image installs Geosupport, builds the project from source using Gradle, and runs geoclient.

A complete Geosupport installation is approximately 2.3 GB in size and adding it directly to the image results in both a very large image and container. In general, prefer adding Geosupport via a named volume.

  1. Build the image from the root of the project.

     docker build -t geoclient:latest-build -f images/build.Dockerfile .
  2. Create and run a temporary container in the background, mapping the container port 8080 to your host port 8080.

     docker run --rm -t -p 8080:8080 geoclient:latest-build
  3. Test the container.

5.5.5. The run image

Runs geoclient using the exploded contents of the spring-boot-packaged jar built from the geoclient-service subproject.

  1. Build the run image from the root of the project.

     docker build -t geoclient:latest-run -f images/run.Dockerfile .

    This assumes you are using the geoclient.jar jar artifact produced by the geoclient/geoclient-service subproject’s Gradle build task. If the the default geoclient-service bootJar artifact <root project>/geoclient-service/libs/geoclient.jar is somewhere else, add a Docker build argument with the path to jar file:

     docker build --build-arg JARFILE=/path/to/geoclient-service.jar -t geoclient:latest-run -f images/run.Dockerfile .
  2. Follow the steps below to create a local volume named geosupport-latest, pre-populated with the uncompressed Geosupport distribution.

  3. Run a temporary container, mounting the local geosupport-latest volume into the container at /opt/geosupport.

     docker run --rm -t --mount source=geosupport-latest,target=/opt/geosupport -p 8080:8080 geoclient:latest-run
  4. Test the container.

5.5.6. Creating a named Geosupport volume

Create a local, named volume containing a Geosupport installation, using the geosupport-docker project. Use the default GEOSUPPORT_BASE path of /opt/geosupport.

   docker volume create geosupport-latest
   docker run --rm --mount source=geosupport-latest,target=/opt/geosupport mlipper/geosupport-docker:latest /bin/true

See the README for geosupport-docker for a more detailed example.

5.5.7. Docker Compose

This section assumes you’ve followed the instructions in The Run Image and Creating a Named Geosupport Volume above. The following objects should be available from your local Docker registry/installation:

  • The geoclient:latest-run image.

  • The geosupport-latest volume.

Note that the GEOCLIENT_IMAGE and GEOSUPPORT_VOLUME environment variables are defaulted to geoclient:latest-run and geosupport-latest, respectively by the images/.env file.

To start the service, run the following from the geoclient project root directory:

docker compose -f images/compose.yaml up

To shut down the service, run:

docker compose -f images/compose.yaml down

5.5.8. Testing the container

This section assumes you are running Geoclient on your workstation, mapped to local port 8080; e.g., by running a container built using build.Dockerfile, run.Dockerfile, or compose.yaml described above.

Geocode a NYC intersection. E.g., "east 53 street and 3rd avenue".

  • Use curl from the command line

    curl 'http://localhost:8080/geoclient/v2/search?input=east%2053%20street%20and%203rd%20avenue'
  • Or use a browser to open the same URL.

5.5.9. About geosupport-docker

The geosupport-docker provides an opinionated, re-packaged version of the official Linux distribution of Geosupport available from New York City’s Department of City Planning. This project’s Docker images depend upon geosupport-docker's CLI scripts and patched C header files for installation, system configuration and native compilation tasks.

Although the geoclient runtime only requires that Geosupport’s shared libraries are accessible to the JVM (via ldconfig, java.library.path, LD_LIBRARY_PATH, etc.) and that the GEOFILES environment variable is set to the absolute path (with an appended '/' character) of Geosupport’s data files, use of geosupport-docker, greatly simplifies the effort of installing and managing Geosupport.

5.6. Kubernetes

This section provides a very basic example of deploying Geoclient to Kubernetes using Minikube. The configuration files are part of the project’s source, located in the <project root>/manifests directory.

This example uses existing Geoclient and Geosupport Docker images that are publicly available on Docker Hub rather than from a local Docker container registry (e.g., Docker Desktop). Although Minikube supports the use of local registries, this requires extra configuration which is beyond the scope of this tutorial.

These are the public Docker Hub registries configured in the kustomization.yaml file:

For information on configuring Minikube to use a local registry, see Minikube’s documentation on configuring registries and pushing images.

5.6.1. Asumptions

This section assumes:

  • Working installation of Minikube.

  • Working installation of kubectl.

    This should be a recent version of kubectl that has built-in support for kustomize.

    Note
    Minikube includes kubectl and it is run using minikube kubectl. This section assumes you’ve either got kubectl installed separately or are using Minikube’s built-in but have aliased minikube kubectl to kubectl.
  • Minikube is using the default, out-of-the-box support for PersistentVolume of type hostPath.

  • Minikube can connect to the Internet to download images from the public geoclient and geosupport-docker registries mentioned above.

5.6.2. Start Minikube

minikube start

5.6.3. Configure kubectl

Configure kubectl to use Minikube. The following assumes you’re using the default context name minikube:

kubectl config use-context minikube

5.6.4. Use kubectl and kustomize to deploy to Minikube

This tutorial uses kustomize to provide a simple templating mechanism which simplifies configuring Geoclient and Geosupport versions and environment variables in a single kustomization.yaml. To run kustomize commands with kubectl, add the -k switch.

From your shell, cd into the <project root>/manifests directory.

If this is the first time you’re deploying Geoclient to this Minikube cluster, some one-time setup is required:

# Create the  gis-apps Namespace
kubectl create -f namespace.yaml

# Create the PersistentVolumeClaim used to mount a Geosupport installation into the Pods' filesystem.
kubectl apply -f pvc-geosupport.yaml

Now use kustomize to template the manifest files (deployment.yaml, hpa.yaml, service.yaml) and apply them with kubectl:

kubectl apply -k .

This will create the geoclient-v2 Service, Deployment, andf HorizontalPodAutoscaling objects. This take a minute or two (depending on your hardware, network connection, Minikube configuration, etc.). The next step requires that all pods be up and running. To see the progress of pod initializations, add the watch switch, -w, to the get pods command:

kubectl get pods -w

NAME                            READY   STATUS     RESTARTS   AGE
geoclient-v2-75899fdc94-drtnn   0/1     Init:0/1   0          16s
geoclient-v2-75899fdc94-p2v5l   0/1     Running    0          31s

In the example above, you can see that one pod is up and running but the other is still initializing.

NAME                            READY   STATUS    RESTARTS      AGE
geoclient-v2-75899fdc94-drtnn   1/1     Running   0             58m
geoclient-v2-75899fdc94-p2v5l   1/1     Running   1 (58m ago)   59m

Once both are running, you need to make the geoclient-v2 service visible to your host machine. To do this, use the kubectl port-forward command. The syntax for this command is kubectl port-forward service/<service name> <host port>:<service port>.

Run:

kubectl port-forward service/geoclient-v2 8081:8080

Note that the kubectl port-forward ... command above will block your terminal (unless you run it in the background by appending a & to the end of the line).

5.6.5. Using different versions of Geoclient or Geosupport

Both geoclient and geosupport-docker are actively developed projects and new versions are being released regularly. kustomize is very useful for "externalizing" the configuration of image tags or environment variables.

Snippet from the kustomization.yaml file:

configMapGenerator:
- name: geosupport-env
  literals:
    - GEOFILES=/opt/geosupport/current/fls/
    - GEOSUPPORT_FULLVERSION=25a1_25.11       # A #
    - GEOSUPPORT_HOME=/opt/geosupport/current

images:
- name: docker.io/mlipper/geosupport-docker
  newTag: 2.0.26                              # B #
- name: docker.io/mlipper/geoclient
  newTag: 2.0.1                               # C #

In the configuration above, A will almost always need to change when B is changed because almost every new geosupport-docker release implies a new version of Geosupport.

C is where the version of the geoclient image is configured. This can change independently of the Geosupport version.

5.6.6. Bask in the glory of your handiwork

Now, geoclient-v2 is running locally, listening on port (<host port>) 8081. By default, geoclient-v2’s base endpoint URL is http://localhost:8081/geoclient/v2.

However, to do anything useful you need to call one of Geoclient’s service endpoints, adding any relevant arguments to the query string.

Try, for example, /version endpoint by opening http://localhost:8081/geoclient/v2/version in your browser.

Try calling the same endpoint from the command line with curl:

curl -s --get http://localhost:8081/geoclient/v2/version
Note
If you’re making Geoclient requests in a browser, the service is exposed with http and not https. Many browsers automatically convert http to https if you’re cutting and pasting or double-clicking a link. Make sure the browser is using the correct scheme if you are having problems.

6. Public Endpoint

This section documents the publicly hosted (and free) Geoclient endpoint.


Getting Access the Geoclient Public Endpoint

Sponsored by NYC’s Office of Technology and Innovation, the Geoclient REST service is freely available to the public on the NYC API Developers Portal.

  1. Go to the NYC API Developers Portal site.

    Home page

  2. If you don’t already have an account, sign up for one by clicking the large green “Sign up” button.

    Signup button

  3. If you are not already logged in, sign in to your account.

  4. Go to the Products page by clicking the “Products” button:

    Products page

  5. Click the Geoclient User link. Make sure to choose the subscription to "Geoclient - v2" as v1 is deprecated and scheduled for deactivation.

    Products button

  6. In the “Your Subscriptions” section of the page, enter the name of the “product” to associate with this Geoclient v2 subscription key and click the “Subscribe” button.

    Subscribe to v2

    Your account can register multiple “products” with different subscription keys for accessing the same API. You can think of a “product” as an application, a project, or a functional use case like “testing”.

  7. You should receive an email notifying you that your subscription has been created.

    Subscription email

  8. Sign in to your account again (if necessary) and follow the “Profile” link in the top right of the page. This page allows you to manage many of your account settings. Go to the “Subscriptions” section and click on “Show” to view your subscription key.

    User profile

6.1. Authentication/Authorization

Geoclient does not perform any kind of authentication or authorization. However, the endpoint that is available to the public (after signing up for access) does sit behind an API gateway. This endpoint requires that an API key be included with every HTTP request.

Although detailed instructions are beyond the scope of this document to provide detailed instructions, each call to the Geoclient public endpoint requires your assigned API key (A.K.A. "subscription key").

  • The recommended way to do this is with an HTTP header named Ocp-Apim-Subscription-Key whose value is your key.

  • At this time, it is possible to submit your key on the HTTP query string using a query string parameter named key (i.e., key=<your_key_goes_here>). However, this method isn’t officially documented by the NYC API Developers Portal so, if possible, prefer the HTTP header method.

See the geoclient-examples repository on GitHub for examples in different programming languages.

7. Contact Us

On GitHub with questions, comments, feature requests, bug reports, threats, etc.


1. See 1B
2. See AP
3. See BL
4. See BN
5. See 3
6. See 3X
7. See 2
8. See 2W