This TypeScript will return JSON result such as:
{
country : { long_name : "someString", short_name : "someStrong" },
city : { long_name : "someString", short_name : "someString" },
state : { long_name : "someString", short_name : "someString" }
}
and can be called using the code : let test = new ZipCodeDeconstructor().deconstruct('20009');
let rp = require('request-promise');
enum IGoogleMapResultType {
COUNTRY = <any>'country',
LOCALITY = <any>'locality',
SUBLOCALITY_LEVEL_1 = <any>'sublocality_level_1',
ADMINISTRATIVE_AREA_LEVEL_1 = <any>'administrative_area_level_1',
// These may be used later, don't delete them, they're for reference
POSTAL_CODE = <any>'postal_code',
NEIGHBORHOOD = <any>'neighborhood',
POLITICAL = <any>'political',
ADMINISTRATIVE_AREA_LEVEL_2 = <any>'administrative_area_level_2',
ADMINISTRATIVE_AREA_LEVEL_3 = <any>'administrative_area_level_3'
}
interface IGoogleMapResult {
address_components : {
long_name? : string
short_name? : string
types : IGoogleMapResultType[]
}[],
formatted_address : string,
geometry: any,
place_id: string,
types: IGoogleMapResultType[]
}
type IGoogleMapResults = any[];
type ZipCodeDeconstructorProperty = {
long_name: string,
short_name: string
}
// What we return from this component
export type ZipCodeDeconstructorResponse = {
city: ZipCodeDeconstructorProperty,
state: ZipCodeDeconstructorProperty,
country: ZipCodeDeconstructorProperty
}
export class ZipCodeDeconstructor {
static apiUrl = "http://maps.googleapis.com/maps/api/geocode/json?address=";
constructor() {}
// main entry point, deconstruct a 5 digit zip into city, state, zip into the corresponding properties
async deconstruct(zip):Promise<ZipCodeDeconstructorResponse> {
let response:any = await this._makeCall(zip);
let firstResult = response.results[0];
let returnObject = {
city : this._extractCity(firstResult),
state : this._extractState(firstResult),
country : this._extractCountry(firstResult)
};
console.log("[Zip Code Deconstructor] returning: ", returnObject);
return returnObject;
}
private _createZipcodeUrl(zip) {
return ZipCodeDeconstructor.apiUrl + zip + '&sensor=true';
}
private async _makeCall(zip) {
return await rp({uri : this._createZipcodeUrl(zip), json : true });
}
private _extractOfTypeFromResult(typesArray:IGoogleMapResultType[], result:IGoogleMapResult) {
for(let i = 0; i < result.address_components.length; i++) {
let addressComponentAtIndex = result.address_components[i];
let type:IGoogleMapResultType = addressComponentAtIndex.types[0];
if(typesArray.indexOf(type) !== -1) {
return {
long_name : addressComponentAtIndex.long_name,
short_name : addressComponentAtIndex.short_name
}
}
}
}
private _extractCity(result:IGoogleMapResult) {
return this._extractOfTypeFromResult([IGoogleMapResultType.SUBLOCALITY_LEVEL_1,
IGoogleMapResultType.LOCALITY], result)
}
private _extractState(result:IGoogleMapResult) {
return this._extractOfTypeFromResult([IGoogleMapResultType.ADMINISTRATIVE_AREA_LEVEL_1], result);
}
private _extractCountry(result:IGoogleMapResult) {
return this._extractOfTypeFromResult([IGoogleMapResultType.COUNTRY], result);
}
}
// let test = new ZipCodeDeconstructor().deconstruct('20009');
The interfaces at the top should help you along the way of understanding what gets returned and what should be passed in.