From 4ae1f9b5b8d006711cd089a1059a7bbc5530d627 Mon Sep 17 00:00:00 2001 From: Giorgos Komninos Date: Thu, 9 Mar 2023 21:20:04 +0200 Subject: [PATCH] Libpostal rest server implementation --- .gitignore | 22 +++ Dockerfile | 41 +++++ README.md | 78 +++++++++- addressparser/addressparser.go | 66 ++++++++ addressparser/libpostal/libpostal.go | 87 +++++++++++ addressparser/ports/http.go | 59 ++++++++ docs/docs.go | 216 +++++++++++++++++++++++++++ docs/swagger.json | 193 ++++++++++++++++++++++++ docs/swagger.yaml | 150 +++++++++++++++++++ go.mod | 44 ++++++ go.sum | 126 ++++++++++++++++ main.go | 75 ++++++++++ 12 files changed, 1156 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 addressparser/addressparser.go create mode 100644 addressparser/libpostal/libpostal.go create mode 100644 addressparser/ports/http.go create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e346019 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bc74e09 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +FROM golang:alpine3.17 + +RUN set -ex \ + && apk add --no-cache --virtual .build-deps \ + curl \ + gcc \ + g++ \ + make \ + libtool \ + autoconf \ + automake \ + git \ + && mkdir -p /src \ + && mkdir -p /data \ + && cd /src \ + && git clone https://github.com/openvenues/libpostal.git \ + && cd libpostal \ + && ./bootstrap.sh \ + && ./configure --datadir=/data MODEL=senzing \ + && make -j "$(nproc)" \ + && make install \ + && apk del .build-deps \ + && rm -rf /src + +RUN apk add --no-cache gcc musl-dev pkgconfig + +WORKDIR /app + +ENV GO111MODULE=on +ENV CGO_ENABLED=1 +ENV GOOS=linux +ENV GOARCH=amd64 + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go build -o /usr/bin/address-parser main.go + +ENTRYPOINT ["/usr/bin/address-parser"] diff --git a/README.md b/README.md index c514fee..2ab7057 100644 --- a/README.md +++ b/README.md @@ -1 +1,77 @@ -# address-parser-go-rest \ No newline at end of file +# Address Parser Go REST + +Address Parser Go REST is a REST API that provides address parsing functionality using the libpostal library. +The purpose of this API is to allow users to easily parse addresses into their individual components +without the need for the libpostal library to be included as a dependency in their projects. + +## Quickstart + +``` +docker run + +curl -X 'POST' \ + 'http://localhost:8080/parse' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "address": "48 Leicester Square, London WC2H 7LU, United Kingdom", + "title_case": true +}' +``` + +Response: + +``` +curl -X 'POST' \ + 'http://localhost:8080/parse' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "address": "48 Leicester Square, London WC2H 7LU, United Kingdom", + "title_case": true +}' +``` + +[swagger documentation](http://localhost:8080/docs/) + + +## Run without docker + +To install and run Address Parser Go REST, you can use the following steps: + +1. Make sure you have a recent version of Golang +2. [Install](https://github.com/openvenues/libpostal/issues#installation-maclinux) libpostal on your machine. +3. `go mod tidy` +4. `go run main.go` + + +Notes: +you can change the port the service or the path for swagger is listening to by setting the following environment variables: +``` +PARSER_HTTP_ADDR=:8080 +DOCS_PATH=/docs +``` +you can also put these in `.env` file in the root of the project. + +If you want to rebuild the swagger documentation make sure that you have +installed [swag](https://github.com/swaggo/swag) + +to regenerate: +``` +go generate +``` + +## Contributing + +If you would like to contribute to Address Parser Go REST, please create a pull request with your changes. +You can also report any issues or bugs you encounter by creating a new issue on the GitHub repository. + +## License + +Address Parser Go REST is licensed under the MIT License. See `LICENSE` for more information. + +## Acknowledgments + +We would like to acknowledge the contributors of the libpostal library and the Go bindings used in this project. + + diff --git a/addressparser/addressparser.go b/addressparser/addressparser.go new file mode 100644 index 0000000..a893b11 --- /dev/null +++ b/addressparser/addressparser.go @@ -0,0 +1,66 @@ +package addressparser + +import "errors" + +var ErrAddressUnparsable = errors.New("address is unparsable") + +// Address is a struct for an address +type Address struct { + // venue name e.g. "Brooklyn Academy of Music", and building names e.g. "Empire State Building" + House string `json:"house,omitempty"` + // for category queries like "restaurants", etc. + Category string `json:"category,omitempty"` + // phrases like "in", "near", etc. used after a category phrase to help with parsing queries like "restaurants in Brooklyn" + Near string `json:"near,omitempty"` + // usually refers to the external (street-facing) building number. In some countries this may be a compount, hyphenated number which also includes an apartment number, or a block number (a la Japan), but libpostal will just call it the house_number for simplicity. + HouseNumber string `json:"house_number,omitempty"` + // street name(s) + Road string `json:"road,omitempty"` + // an apartment, unit, office, lot, or other secondary unit designator + Unit string `json:"unit,omitempty"` + // expressions indicating a floor number e.g. "3rd Floor", "Ground Floor", etc. + Level string `json:"level,omitempty"` + // numbered/lettered staircase + Staircase string `json:"staircase,omitempty"` + // numbered/lettered entrance + Entrance string `json:"entrance,omitempty"` + // post office box: typically found in non-physical (mail-only) addresses + PoBox string `json:"po_box,omitempty"` + // postal codes used for mail sorting + Postcode string `json:"postcode,omitempty"` + // usually an unofficial neighborhood name like "Harlem", "South Bronx", or "Crown Heights" + Suburb string `json:"suburb,omitempty"` + // these are usually boroughs or districts within a city that serve some official purpose e.g. "Brooklyn" or "Hackney" or "Bratislava IV" + CityDistrict string `json:"city_district,omitempty"` + // any human settlement including cities, towns, villages, hamlets, localities, etc. + City string `json:"city,omitempty"` + // named islands e.g. "Maui" + Island string `json:"island,omitempty"` + // usually a second-level administrative division or county. + StateDistrict string `json:"state_district,omitempty"` + // a first-level administrative division. Scotland, Northern Ireland, Wales, and England in the UK are mapped to "state" as well (convention used in OSM, GeoPlanet, etc.) + State string `json:"state,omitempty"` + // informal subdivision of a country without any political status + CountryRegion string `json:"country_region,omitempty"` + // sovereign nations and their dependent territories, anything with an ISO-3166 code. + Country string `json:"country,omitempty"` + // currently only used for appending “West Indies” after the country name, a pattern frequently used in the English-speaking Caribbean e.g. “Jamaica, West Indies” + WorldRegion string `json:"world_region,omitempty"` +} + +// AddressParserInput is a struct for the input to the address parser +type AddressParserInput struct { + // the address to parse + Address string `json:"address" validate:"required"` + // the language of the address. Leave empty if you don't know + Language string `json:"language,omitempty"` + // the country of the address. Leave empty if you don't know + Country string `json:"country,omitempty"` + // if true then the responses will be title Cased. Default behavior of libpostal is not to do that. + TitleCase bool `json:"title_case,omitempty"` +} + +// AddressParser is an interface for the address parser +type AddressParser interface { + Parse(input AddressParserInput) (Address, error) +} diff --git a/addressparser/libpostal/libpostal.go b/addressparser/libpostal/libpostal.go new file mode 100644 index 0000000..f9acb4b --- /dev/null +++ b/addressparser/libpostal/libpostal.go @@ -0,0 +1,87 @@ +package libpostal + +import ( + "github.com/gosom/kit/logging" + postal "github.com/openvenues/gopostal/parser" + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "github.com/gosom/address-parser-go-rest/addressparser" +) + +var _ addressparser.AddressParser = (*libPostalParser)(nil) + +type libPostalParser struct { + log logging.Logger +} + +func (o *libPostalParser) Parse(input addressparser.AddressParserInput) (addressparser.Address, error) { + components := postal.ParseAddressOptions(input.Address, postal.ParserOptions{ + Language: input.Language, + Country: input.Country, + }) + if len(components) == 0 { + return addressparser.Address{}, addressparser.ErrAddressUnparsable + } + address := addressparser.Address{} + tag := language.Und + if input.Language != "" { + if r, err := language.Parse("de"); err == nil { + tag = r + } + } + for i := range components { + if input.TitleCase { + components[i].Value = cases.Title(tag, cases.NoLower).String(components[i].Value) + } + switch components[i].Label { + case "house": + address.House = components[i].Value + case "category": + address.Category = components[i].Value + case "near": + address.Near = components[i].Value + case "house_number": + address.HouseNumber = components[i].Value + case "road": + address.Road = components[i].Value + case "unit": + address.Unit = components[i].Value + case "level": + address.Level = components[i].Value + case "staircase": + address.Staircase = components[i].Value + case "entrance": + address.Entrance = components[i].Value + case "po_box": + address.PoBox = components[i].Value + case "postcode": + address.Postcode = components[i].Value + case "suburb": + address.Suburb = components[i].Value + case "city_district": + address.CityDistrict = components[i].Value + case "city": + address.City = components[i].Value + case "island": + address.Island = components[i].Value + case "state_district": + address.StateDistrict = components[i].Value + case "state": + address.State = components[i].Value + case "country_region": + address.CountryRegion = components[i].Value + case "country": + address.Country = components[i].Value + case "world_region": + address.WorldRegion = components[i].Value + default: + o.log.Warn("Unknown component", "component", components[i].Label) + } + } + return address, nil +} + +func NewLibPostalParser(log logging.Logger) *libPostalParser { + return &libPostalParser{log: log} +} diff --git a/addressparser/ports/http.go b/addressparser/ports/http.go new file mode 100644 index 0000000..7bb4577 --- /dev/null +++ b/addressparser/ports/http.go @@ -0,0 +1,59 @@ +package ports + +import ( + "fmt" + "net/http" + + "github.com/gosom/kit/lib" + "github.com/gosom/kit/logging" + "github.com/gosom/kit/web" + + "github.com/gosom/address-parser-go-rest/addressparser" +) + +// AddressParserHandler is a handler for parsing addresses +type AddressParserHandler struct { + log logging.Logger + parser addressparser.AddressParser +} + +// NewAddressParserHandler creates a new AddressParserHandler +func NewAddressParserHandler(log logging.Logger, parser addressparser.AddressParser) AddressParserHandler { + return AddressParserHandler{ + log: log, + parser: parser, + } +} + +// RegisterRoutes registers the routes for the AddressParserHandler +func (o *AddressParserHandler) RegisterRouters(r web.Router) { + r.Post("/parse", o.Parse) +} + +// Parse is a handler for parsing addresses +// +// @Summary Parse an address into its components +// @Description Parses an address into its components +// @Tags AddressParser +// @Accept json +// @Produce json +// @Param input body addressparser.AddressParserInput true "AddressParserInput" +// @Success 200 {object} addressparser.Address +// @Failure 400 {object} web.ErrResponse +// @Failure 422 {object} web.ErrResponse +// @Failure 500 {object} web.ErrResponse +// @Router /parse [post] +func (o *AddressParserHandler) Parse(w http.ResponseWriter, r *http.Request) { + var payload addressparser.AddressParserInput + if err := web.DecodeBody(r, &payload, true); err != nil { + web.JSONError(w, r, fmt.Errorf("%w %s", lib.ErrBadRequest)) + return + } + result, err := o.parser.Parse(payload) + if err != nil { + ae := fmt.Errorf("%w %s", lib.ErrUnprocessable, err.Error()) + web.JSONError(w, r, ae) + return + } + web.JSON(w, r, http.StatusOK, result) +} diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..8cd32f5 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,216 @@ +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "Giorgos Komninos", + "url": "http://blog.gkomninos.com" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/parse": { + "post": { + "description": "Parses an address into its components", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AddressParser" + ], + "summary": "Parse an address into its components", + "parameters": [ + { + "description": "AddressParserInput", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/addressparser.AddressParserInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/addressparser.Address" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + } + } + } + } + }, + "definitions": { + "addressparser.Address": { + "type": "object", + "properties": { + "category": { + "description": "for category queries like \"restaurants\", etc.", + "type": "string" + }, + "city": { + "description": "any human settlement including cities, towns, villages, hamlets, localities, etc.", + "type": "string" + }, + "city_district": { + "description": "these are usually boroughs or districts within a city that serve some official purpose e.g. \"Brooklyn\" or \"Hackney\" or \"Bratislava IV\"", + "type": "string" + }, + "country": { + "description": "sovereign nations and their dependent territories, anything with an ISO-3166 code.", + "type": "string" + }, + "country_region": { + "description": "informal subdivision of a country without any political status", + "type": "string" + }, + "entrance": { + "description": "numbered/lettered entrance", + "type": "string" + }, + "house": { + "description": "venue name e.g. \"Brooklyn Academy of Music\", and building names e.g. \"Empire State Building\"", + "type": "string" + }, + "house_number": { + "description": "usually refers to the external (street-facing) building number. In some countries this may be a compount, hyphenated number which also includes an apartment number, or a block number (a la Japan), but libpostal will just call it the house_number for simplicity.", + "type": "string" + }, + "island": { + "description": "named islands e.g. \"Maui\"", + "type": "string" + }, + "level": { + "description": "expressions indicating a floor number e.g. \"3rd Floor\", \"Ground Floor\", etc.", + "type": "string" + }, + "near": { + "description": "phrases like \"in\", \"near\", etc. used after a category phrase to help with parsing queries like \"restaurants in Brooklyn\"", + "type": "string" + }, + "po_box": { + "description": "post office box: typically found in non-physical (mail-only) addresses", + "type": "string" + }, + "postcode": { + "description": "postal codes used for mail sorting", + "type": "string" + }, + "road": { + "description": "street name(s)", + "type": "string" + }, + "staircase": { + "description": "numbered/lettered staircase", + "type": "string" + }, + "state": { + "description": "a first-level administrative division. Scotland, Northern Ireland, Wales, and England in the UK are mapped to \"state\" as well (convention used in OSM, GeoPlanet, etc.)", + "type": "string" + }, + "state_district": { + "description": "usually a second-level administrative division or county.", + "type": "string" + }, + "suburb": { + "description": "usually an unofficial neighborhood name like \"Harlem\", \"South Bronx\", or \"Crown Heights\"", + "type": "string" + }, + "unit": { + "description": "an apartment, unit, office, lot, or other secondary unit designator", + "type": "string" + }, + "world_region": { + "description": "currently only used for appending “West Indies” after the country name, a pattern frequently used in the English-speaking Caribbean e.g. “Jamaica, West Indies”", + "type": "string" + } + } + }, + "addressparser.AddressParserInput": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + }, + "country": { + "type": "string" + }, + "language": { + "type": "string" + }, + "title_case": { + "description": "if true then the responses will be title Cased. Default behavior of libpostal is not to do that.", + "type": "boolean" + } + } + }, + "web.ErrResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0.0", + Host: "localhost:8080", + BasePath: "/", + Schemes: []string{}, + Title: "Address Parser API", + Description: "This is the API for the address parser service", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..7eb9f50 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,193 @@ +{ + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "swagger": "2.0", + "info": { + "description": "This is the API for the address parser service", + "title": "Address Parser API", + "contact": { + "name": "Giorgos Komninos", + "url": "http://blog.gkomninos.com" + }, + "version": "1.0.0" + }, + "host": "localhost:8080", + "basePath": "/", + "paths": { + "/parse": { + "post": { + "description": "Parses an address into its components", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AddressParser" + ], + "summary": "Parse an address into its components", + "parameters": [ + { + "description": "AddressParserInput", + "name": "input", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/addressparser.AddressParserInput" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/addressparser.Address" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/web.ErrResponse" + } + } + } + } + } + }, + "definitions": { + "addressparser.Address": { + "type": "object", + "properties": { + "category": { + "description": "for category queries like \"restaurants\", etc.", + "type": "string" + }, + "city": { + "description": "any human settlement including cities, towns, villages, hamlets, localities, etc.", + "type": "string" + }, + "city_district": { + "description": "these are usually boroughs or districts within a city that serve some official purpose e.g. \"Brooklyn\" or \"Hackney\" or \"Bratislava IV\"", + "type": "string" + }, + "country": { + "description": "sovereign nations and their dependent territories, anything with an ISO-3166 code.", + "type": "string" + }, + "country_region": { + "description": "informal subdivision of a country without any political status", + "type": "string" + }, + "entrance": { + "description": "numbered/lettered entrance", + "type": "string" + }, + "house": { + "description": "venue name e.g. \"Brooklyn Academy of Music\", and building names e.g. \"Empire State Building\"", + "type": "string" + }, + "house_number": { + "description": "usually refers to the external (street-facing) building number. In some countries this may be a compount, hyphenated number which also includes an apartment number, or a block number (a la Japan), but libpostal will just call it the house_number for simplicity.", + "type": "string" + }, + "island": { + "description": "named islands e.g. \"Maui\"", + "type": "string" + }, + "level": { + "description": "expressions indicating a floor number e.g. \"3rd Floor\", \"Ground Floor\", etc.", + "type": "string" + }, + "near": { + "description": "phrases like \"in\", \"near\", etc. used after a category phrase to help with parsing queries like \"restaurants in Brooklyn\"", + "type": "string" + }, + "po_box": { + "description": "post office box: typically found in non-physical (mail-only) addresses", + "type": "string" + }, + "postcode": { + "description": "postal codes used for mail sorting", + "type": "string" + }, + "road": { + "description": "street name(s)", + "type": "string" + }, + "staircase": { + "description": "numbered/lettered staircase", + "type": "string" + }, + "state": { + "description": "a first-level administrative division. Scotland, Northern Ireland, Wales, and England in the UK are mapped to \"state\" as well (convention used in OSM, GeoPlanet, etc.)", + "type": "string" + }, + "state_district": { + "description": "usually a second-level administrative division or county.", + "type": "string" + }, + "suburb": { + "description": "usually an unofficial neighborhood name like \"Harlem\", \"South Bronx\", or \"Crown Heights\"", + "type": "string" + }, + "unit": { + "description": "an apartment, unit, office, lot, or other secondary unit designator", + "type": "string" + }, + "world_region": { + "description": "currently only used for appending “West Indies” after the country name, a pattern frequently used in the English-speaking Caribbean e.g. “Jamaica, West Indies”", + "type": "string" + } + } + }, + "addressparser.AddressParserInput": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + }, + "country": { + "type": "string" + }, + "language": { + "type": "string" + }, + "title_case": { + "description": "if true then the responses will be title Cased. Default behavior of libpostal is not to do that.", + "type": "boolean" + } + } + }, + "web.ErrResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..661acea --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,150 @@ +basePath: / +consumes: +- application/json +definitions: + addressparser.Address: + properties: + category: + description: for category queries like "restaurants", etc. + type: string + city: + description: any human settlement including cities, towns, villages, hamlets, + localities, etc. + type: string + city_district: + description: these are usually boroughs or districts within a city that serve + some official purpose e.g. "Brooklyn" or "Hackney" or "Bratislava IV" + type: string + country: + description: sovereign nations and their dependent territories, anything with + an ISO-3166 code. + type: string + country_region: + description: informal subdivision of a country without any political status + type: string + entrance: + description: numbered/lettered entrance + type: string + house: + description: venue name e.g. "Brooklyn Academy of Music", and building names + e.g. "Empire State Building" + type: string + house_number: + description: usually refers to the external (street-facing) building number. + In some countries this may be a compount, hyphenated number which also includes + an apartment number, or a block number (a la Japan), but libpostal will + just call it the house_number for simplicity. + type: string + island: + description: named islands e.g. "Maui" + type: string + level: + description: expressions indicating a floor number e.g. "3rd Floor", "Ground + Floor", etc. + type: string + near: + description: phrases like "in", "near", etc. used after a category phrase + to help with parsing queries like "restaurants in Brooklyn" + type: string + po_box: + description: 'post office box: typically found in non-physical (mail-only) + addresses' + type: string + postcode: + description: postal codes used for mail sorting + type: string + road: + description: street name(s) + type: string + staircase: + description: numbered/lettered staircase + type: string + state: + description: a first-level administrative division. Scotland, Northern Ireland, + Wales, and England in the UK are mapped to "state" as well (convention used + in OSM, GeoPlanet, etc.) + type: string + state_district: + description: usually a second-level administrative division or county. + type: string + suburb: + description: usually an unofficial neighborhood name like "Harlem", "South + Bronx", or "Crown Heights" + type: string + unit: + description: an apartment, unit, office, lot, or other secondary unit designator + type: string + world_region: + description: currently only used for appending “West Indies” after the country + name, a pattern frequently used in the English-speaking Caribbean e.g. “Jamaica, + West Indies” + type: string + type: object + addressparser.AddressParserInput: + properties: + address: + type: string + country: + type: string + language: + type: string + title_case: + description: if true then the responses will be title Cased. Default behavior + of libpostal is not to do that. + type: boolean + required: + - address + type: object + web.ErrResponse: + properties: + code: + type: integer + message: + type: string + type: object +host: localhost:8080 +info: + contact: + name: Giorgos Komninos + url: http://blog.gkomninos.com + description: This is the API for the address parser service + title: Address Parser API + version: 1.0.0 +paths: + /parse: + post: + consumes: + - application/json + description: Parses an address into its components + parameters: + - description: AddressParserInput + in: body + name: input + required: true + schema: + $ref: '#/definitions/addressparser.AddressParserInput' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/addressparser.Address' + "400": + description: Bad Request + schema: + $ref: '#/definitions/web.ErrResponse' + "422": + description: Unprocessable Entity + schema: + $ref: '#/definitions/web.ErrResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/web.ErrResponse' + summary: Parse an address into its components + tags: + - AddressParser +produces: +- application/json +swagger: "2.0" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7e3b233 --- /dev/null +++ b/go.mod @@ -0,0 +1,44 @@ +module github.com/gosom/address-parser-go-rest + +go 1.20 + +require ( + github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a + github.com/joho/godotenv v1.5.1 + github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d + github.com/swaggo/swag v1.8.10 + golang.org/x/text v0.8.0 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/go-chi/chi/v5 v5.0.8 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/ismurov/swaggerui v0.2.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/leodido/go-urn v1.2.2 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/oklog/ulid/v2 v2.1.0 // indirect + github.com/realclientip/realclientip-go v1.0.0 // indirect + github.com/rs/cors v1.8.3 // indirect + github.com/rs/xid v1.4.0 // indirect + github.com/rs/zerolog v1.29.0 // indirect + github.com/wagslane/go-password-validator v0.3.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/tools v0.6.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fd578e5 --- /dev/null +++ b/go.sum @@ -0,0 +1,126 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a h1:5tcB33GTXm0pFUiEFpmE91tMsHQj+I+W7zubT8J/ugI= +github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a/go.mod h1:ngnWSsuBEpCA5Y43kZRa3x8RBYZZ4LDtvZHO4N5dHZ0= +github.com/ismurov/swaggerui v0.2.0 h1:rx/BTbufsCUMq0G2a0Cmd045nkrRmHBa7T249wqnVBM= +github.com/ismurov/swaggerui v0.2.0/go.mod h1:EaaariTC2xXLMsKU9v3MdYT62/akXBvRFxmuY9zyqF0= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= +github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= +github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d h1:KJ+N55d9zLN8fTg3NchLdmmAmPieXC5E6UNJ8zFFttU= +github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d/go.mod h1:Ycrd7XnwQdumHzpB/6WEa85B4WNdbLC6Wz4FAQNkaV0= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/realclientip/realclientip-go v1.0.0 h1:+yPxeC0mEaJzq1BfCt2h4BxlyrvIIBzR6suDc3BEF1U= +github.com/realclientip/realclientip-go v1.0.0/go.mod h1:CXnUdVwFRcXFJIRb/dTYqbT7ud48+Pi2pFm80bxDmcI= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= +github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/swaggo/swag v1.8.10 h1:eExW4bFa52WOjqRzRD58bgWsWfdFJso50lpbeTcmTfo= +github.com/swaggo/swag v1.8.10/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= +github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I= +github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..c2b967a --- /dev/null +++ b/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "embed" + "os" + + "github.com/gosom/kit/logging" + "github.com/gosom/kit/web" + "github.com/joho/godotenv" + + "github.com/gosom/address-parser-go-rest/addressparser/libpostal" + "github.com/gosom/address-parser-go-rest/addressparser/ports" +) + +//go:generate swag i -g main.go --pd + +//go:embed docs/swagger.json +var specFs embed.FS + +// @title Address Parser API +// @version 1.0.0 +// @description This is the API for the address parser service + +// @contact.name Giorgos Komninos +// @contact.url http://blog.gkomninos.com + +// @host localhost:8080 +// @BasePath / +// @accept json +// @produce json +// @query.collection.format multi +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if err := run(ctx); err != nil { + panic(err) + } +} + +func run(ctx context.Context) error { + if err := godotenv.Load(); err != nil { + return err + } + docPath := os.Getenv("DOCS_PATH") + if docPath == "" { + docPath = "/docs" + } + routerCfg := web.RouterConfig{ + SwaggerUI: &web.SwaggerUIConfig{ + SpecName: "AddressParser API", + SpecFile: "/docs/swagger.json", + Path: docPath, + SpecFS: specFs, + }, + } + router := web.NewRouter(routerCfg) + + log := logging.Get() + + parser := libpostal.NewLibPostalParser(log.With("component", "libpostal")) + hn := ports.NewAddressParserHandler(log.With("component", "handler"), parser) + hn.RegisterRouters(router) + addr := os.Getenv("PARSER_HTTP_ADDR") + if addr == "" { + addr = ":8080" + } + webCfg := web.ServerConfig{ + Host: addr, + Router: router, + } + webSvc := web.NewHttpServer(webCfg) + + return webSvc.ListenAndServe(ctx) +}