├── .gitignore ├── .github └── workflows │ └── build.yml ├── Dockerfile ├── LICENSE ├── go.mod ├── addressparser ├── ports │ └── http.go ├── libpostal │ └── libpostal.go └── addressparser.go ├── main.go ├── README.md ├── docs ├── swagger.yaml ├── swagger.json └── docs.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | .env 23 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | permissions: {} 4 | 5 | on: 6 | push: 7 | branches: [main] 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | run: 13 | name: Build 14 | runs-on: ubuntu-latest 15 | timeout-minutes: 7 16 | strategy: 17 | fail-fast: true 18 | matrix: 19 | go: ['>=1.20.0'] 20 | 21 | steps: 22 | - name: Check out code 23 | uses: actions/checkout@v3 24 | 25 | - name: Install Go 26 | uses: actions/setup-go@v4 27 | with: 28 | go-version: ${{ matrix.go }} 29 | check-latest: true 30 | 31 | - name: Go Format 32 | run: gofmt -s -w . && git diff --exit-code 33 | 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine3.17 2 | 3 | RUN set -ex \ 4 | && apk add --no-cache --virtual .build-deps \ 5 | curl \ 6 | gcc \ 7 | g++ \ 8 | make \ 9 | libtool \ 10 | autoconf \ 11 | automake \ 12 | git \ 13 | && mkdir -p /src \ 14 | && mkdir -p /data \ 15 | && cd /src \ 16 | && git clone https://github.com/openvenues/libpostal.git \ 17 | && cd libpostal \ 18 | && ./bootstrap.sh \ 19 | && ./configure --datadir=/data MODEL=senzing \ 20 | && make -j "$(nproc)" \ 21 | && make install \ 22 | && apk del .build-deps \ 23 | && rm -rf /src 24 | 25 | RUN apk add --no-cache gcc musl-dev pkgconfig 26 | 27 | WORKDIR /app 28 | 29 | ENV GO111MODULE=on 30 | ENV CGO_ENABLED=1 31 | ENV GOOS=linux 32 | ENV GOARCH=amd64 33 | 34 | COPY go.mod go.sum ./ 35 | RUN go mod download 36 | 37 | COPY . . 38 | 39 | RUN go build -o /usr/bin/address-parser main.go 40 | 41 | ENTRYPOINT ["/usr/bin/address-parser"] 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Georgios Komninos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gosom/address-parser-go-rest 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a 7 | github.com/joho/godotenv v1.5.1 8 | github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d 9 | github.com/swaggo/swag v1.8.10 10 | golang.org/x/text v0.8.0 11 | ) 12 | 13 | require ( 14 | github.com/KyleBanks/depth v1.2.1 // indirect 15 | github.com/PuerkitoBio/purell v1.1.1 // indirect 16 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect 17 | github.com/go-chi/chi/v5 v5.0.8 // indirect 18 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 19 | github.com/go-openapi/jsonreference v0.19.6 // indirect 20 | github.com/go-openapi/spec v0.20.4 // indirect 21 | github.com/go-openapi/swag v0.19.15 // indirect 22 | github.com/go-playground/locales v0.14.1 // indirect 23 | github.com/go-playground/universal-translator v0.18.1 // indirect 24 | github.com/go-playground/validator/v10 v10.11.2 // indirect 25 | github.com/google/uuid v1.3.0 // indirect 26 | github.com/ismurov/swaggerui v0.2.0 // indirect 27 | github.com/josharian/intern v1.0.0 // indirect 28 | github.com/kelseyhightower/envconfig v1.4.0 // indirect 29 | github.com/leodido/go-urn v1.2.2 // indirect 30 | github.com/mailru/easyjson v0.7.6 // indirect 31 | github.com/mattn/go-colorable v0.1.13 // indirect 32 | github.com/mattn/go-isatty v0.0.17 // indirect 33 | github.com/oklog/ulid/v2 v2.1.0 // indirect 34 | github.com/realclientip/realclientip-go v1.0.0 // indirect 35 | github.com/rs/cors v1.8.3 // indirect 36 | github.com/rs/xid v1.4.0 // indirect 37 | github.com/rs/zerolog v1.29.0 // indirect 38 | github.com/wagslane/go-password-validator v0.3.0 // indirect 39 | golang.org/x/crypto v0.7.0 // indirect 40 | golang.org/x/net v0.8.0 // indirect 41 | golang.org/x/sys v0.6.0 // indirect 42 | golang.org/x/tools v0.6.0 // indirect 43 | gopkg.in/yaml.v2 v2.4.0 // indirect 44 | ) 45 | -------------------------------------------------------------------------------- /addressparser/ports/http.go: -------------------------------------------------------------------------------- 1 | package ports 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/gosom/kit/lib" 8 | "github.com/gosom/kit/logging" 9 | "github.com/gosom/kit/web" 10 | 11 | "github.com/gosom/address-parser-go-rest/addressparser" 12 | ) 13 | 14 | // AddressParserHandler is a handler for parsing addresses 15 | type AddressParserHandler struct { 16 | log logging.Logger 17 | parser addressparser.AddressParser 18 | } 19 | 20 | // NewAddressParserHandler creates a new AddressParserHandler 21 | func NewAddressParserHandler(log logging.Logger, parser addressparser.AddressParser) AddressParserHandler { 22 | return AddressParserHandler{ 23 | log: log, 24 | parser: parser, 25 | } 26 | } 27 | 28 | // RegisterRoutes registers the routes for the AddressParserHandler 29 | func (o *AddressParserHandler) RegisterRouters(r web.Router) { 30 | r.Post("/parse", o.Parse) 31 | } 32 | 33 | // Parse is a handler for parsing addresses 34 | // 35 | // @Summary Parse an address into its components 36 | // @Description Parses an address into its components 37 | // @Tags AddressParser 38 | // @Accept json 39 | // @Produce json 40 | // @Param input body addressparser.AddressParserInput true "AddressParserInput" 41 | // @Success 200 {object} addressparser.Address 42 | // @Failure 400 {object} web.ErrResponse 43 | // @Failure 422 {object} web.ErrResponse 44 | // @Failure 500 {object} web.ErrResponse 45 | // @Router /parse [post] 46 | func (o *AddressParserHandler) Parse(w http.ResponseWriter, r *http.Request) { 47 | var payload addressparser.AddressParserInput 48 | if err := web.DecodeBody(r, &payload, true); err != nil { 49 | web.JSONError(w, r, fmt.Errorf("%w %s", lib.ErrBadRequest, err)) 50 | return 51 | } 52 | result, err := o.parser.Parse(payload) 53 | if err != nil { 54 | ae := fmt.Errorf("%w %s", lib.ErrUnprocessable, err.Error()) 55 | web.JSONError(w, r, ae) 56 | return 57 | } 58 | web.JSON(w, r, http.StatusOK, result) 59 | } 60 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "embed" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/gosom/kit/logging" 10 | "github.com/gosom/kit/web" 11 | "github.com/joho/godotenv" 12 | 13 | "github.com/gosom/address-parser-go-rest/addressparser/libpostal" 14 | "github.com/gosom/address-parser-go-rest/addressparser/ports" 15 | ) 16 | 17 | //go:generate swag i -g main.go --pd 18 | 19 | //go:embed docs/swagger.json 20 | var specFs embed.FS 21 | 22 | // @title Address Parser API 23 | // @version 1.0.0 24 | // @description This is the API for the address parser service 25 | 26 | // @contact.name Giorgos Komninos 27 | // @contact.url http://blog.gkomninos.com 28 | 29 | // @host localhost:8080 30 | // @BasePath / 31 | // @accept json 32 | // @produce json 33 | // @query.collection.format multi 34 | func main() { 35 | ctx, cancel := context.WithCancel(context.Background()) 36 | defer cancel() 37 | if err := run(ctx); err != nil { 38 | panic(err) 39 | } 40 | } 41 | 42 | func run(ctx context.Context) error { 43 | if err := godotenv.Load(); err != nil { 44 | return err 45 | } 46 | docPath := os.Getenv("DOCS_PATH") 47 | if docPath == "" { 48 | docPath = "/docs" 49 | } 50 | routerCfg := web.RouterConfig{ 51 | SwaggerUI: &web.SwaggerUIConfig{ 52 | SpecName: "AddressParser API", 53 | SpecFile: "/docs/swagger.json", 54 | Path: docPath, 55 | SpecFS: specFs, 56 | }, 57 | } 58 | router := web.NewRouter(routerCfg) 59 | 60 | log := logging.Get() 61 | 62 | parser := libpostal.NewLibPostalParser(log.With("component", "libpostal")) 63 | hn := ports.NewAddressParserHandler(log.With("component", "handler"), parser) 64 | hn.RegisterRouters(router) 65 | addr := os.Getenv("PARSER_HTTP_ADDR") 66 | if addr == "" { 67 | addr = ":8080" 68 | } 69 | webCfg := web.ServerConfig{ 70 | Host: addr, 71 | Router: router, 72 | } 73 | log.Info(fmt.Sprintf("Starting server at %s", addr)) 74 | webSvc := web.NewHttpServer(webCfg) 75 | 76 | return webSvc.ListenAndServe(ctx) 77 | } 78 | -------------------------------------------------------------------------------- /addressparser/libpostal/libpostal.go: -------------------------------------------------------------------------------- 1 | package libpostal 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/gosom/kit/logging" 7 | postal "github.com/openvenues/gopostal/parser" 8 | "golang.org/x/text/cases" 9 | "golang.org/x/text/language" 10 | 11 | "github.com/gosom/address-parser-go-rest/addressparser" 12 | ) 13 | 14 | var _ addressparser.AddressParser = (*libPostalParser)(nil) 15 | 16 | type libPostalParser struct { 17 | log logging.Logger 18 | } 19 | 20 | func (o *libPostalParser) Parse(input addressparser.AddressParserInput) (addressparser.Address, error) { 21 | components := postal.ParseAddressOptions(input.Address, postal.ParserOptions{ 22 | Language: input.Language, 23 | Country: input.Country, 24 | }) 25 | if len(components) == 0 { 26 | return addressparser.Address{}, addressparser.ErrAddressUnparsable 27 | } 28 | address := addressparser.Address{} 29 | tag := language.Und 30 | if input.Language != "" { 31 | if r, err := language.Parse("de"); err == nil { 32 | tag = r 33 | } 34 | } 35 | houseNumberFound := false 36 | for i := range components { 37 | if input.TitleCase { 38 | components[i].Value = cases.Title(tag, cases.NoLower).String(components[i].Value) 39 | } 40 | switch components[i].Label { 41 | case "house": 42 | address.House = components[i].Value 43 | case "category": 44 | address.Category = components[i].Value 45 | case "near": 46 | address.Near = components[i].Value 47 | case "house_number": 48 | if !houseNumberFound { 49 | address.HouseNumber = components[i].Value 50 | houseNumberFound = true 51 | } 52 | case "road": 53 | address.Road = components[i].Value 54 | case "unit": 55 | address.Unit = components[i].Value 56 | case "level": 57 | address.Level = components[i].Value 58 | case "staircase": 59 | address.Staircase = components[i].Value 60 | case "entrance": 61 | address.Entrance = components[i].Value 62 | case "po_box": 63 | address.PoBox = components[i].Value 64 | case "postcode": 65 | address.Postcode = components[i].Value 66 | case "suburb": 67 | address.Suburb = components[i].Value 68 | case "city_district": 69 | address.CityDistrict = components[i].Value 70 | case "city": 71 | address.City = components[i].Value 72 | case "island": 73 | address.Island = components[i].Value 74 | case "state_district": 75 | address.StateDistrict = components[i].Value 76 | case "state": 77 | address.State = components[i].Value 78 | case "country_region": 79 | address.CountryRegion = components[i].Value 80 | case "country": 81 | address.Country = components[i].Value 82 | case "world_region": 83 | address.WorldRegion = components[i].Value 84 | default: 85 | o.log.Warn("Unknown component", "component", components[i].Label) 86 | } 87 | 88 | component := addressparser.AddressComponent{ 89 | Label: components[i].Label, 90 | Value: components[i].Value, 91 | } 92 | address.Components = append(address.Components, component) 93 | } 94 | address.HouseNumber = strings.TrimSpace(address.HouseNumber) 95 | return address, nil 96 | } 97 | 98 | func NewLibPostalParser(log logging.Logger) *libPostalParser { 99 | return &libPostalParser{log: log} 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Address Parser Go REST 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/gosom/address-parser-go-rest)](https://goreportcard.com/report/github.com/gosom/address-parser-go-rest) 3 | 4 | 5 | Address Parser Go REST is a REST API that provides address parsing functionality using the libpostal library. 6 | The purpose of this API is to allow users to easily parse addresses into their individual components 7 | without the need for the libpostal library to be included as a dependency in their projects. 8 | 9 | ## Quickstart 10 | 11 | ``` 12 | docker run -p 8080:8080 gosom/address-parser-go-rest 13 | ``` 14 | 15 | This will take some time to load 16 | 17 | then try a sample request 18 | 19 | ``` 20 | curl -X 'POST' \ 21 | 'http://localhost:8080/parse' \ 22 | -H 'accept: application/json' \ 23 | -H 'Content-Type: application/json' \ 24 | -d '{ 25 | "address": "48 Leicester Square, London WC2H 7LU, United Kingdom", 26 | "title_case": true 27 | }' 28 | ``` 29 | 30 | Response: 31 | 32 | ``` 33 | { 34 | "house_number": "48", 35 | "road": "Leicester Square", 36 | "postcode": "Wc2h 7Lu", 37 | "city": "London", 38 | "country": "United Kingdom", 39 | "components": [ 40 | { 41 | "label": "house_number", 42 | "value": "48" 43 | }, 44 | { 45 | "label": "road", 46 | "value": "Leicester Square" 47 | }, 48 | { 49 | "label": "city", 50 | "value": "London" 51 | }, 52 | { 53 | "label": "postcode", 54 | "value": "Wc2h 7Lu" 55 | }, 56 | { 57 | "label": "country", 58 | "value": "United Kingdom" 59 | } 60 | ] 61 | } 62 | ``` 63 | 64 | Open [swagger documentation] (http://localhost:8080/docs/) 65 | 66 | See another example [in this blog post](https://blog.gkomninos.com/introducing-address-parser-go-rest-a-simple-solution-for-address-parsing) 67 | 68 | 69 | ## Run without docker 70 | 71 | To install and run Address Parser Go REST, you can use the following steps: 72 | 73 | 1. Make sure you have a recent version of Golang 74 | 2. [Install](https://github.com/openvenues/libpostal/issues#installation-maclinux) libpostal on your machine. 75 | 3. `go mod tidy` 76 | 4. `go run main.go` 77 | 78 | 79 | Notes: 80 | you can change the port the service or the path for swagger is listening to by setting the following environment variables: 81 | ``` 82 | PARSER_HTTP_ADDR=:8080 83 | DOCS_PATH=/docs 84 | ``` 85 | you can also put these in `.env` file in the root of the project. 86 | 87 | If you want to rebuild the swagger documentation make sure that you have 88 | installed [swag](https://github.com/swaggo/swag) 89 | 90 | to regenerate: 91 | ``` 92 | go generate 93 | ``` 94 | 95 | ## Contributing 96 | 97 | If you would like to contribute to Address Parser Go REST, please create a pull request with your changes. 98 | You can also report any issues or bugs you encounter by creating a new issue on the GitHub repository. 99 | 100 | ## License 101 | 102 | Address Parser Go REST is licensed under the MIT License. See `LICENSE` for more information. 103 | 104 | ## Acknowledgments 105 | 106 | We would like to acknowledge the contributors of the libpostal library and the Go bindings used in this project. 107 | 108 | 109 | -------------------------------------------------------------------------------- /addressparser/addressparser.go: -------------------------------------------------------------------------------- 1 | package addressparser 2 | 3 | import "errors" 4 | 5 | var ErrAddressUnparsable = errors.New("address is unparsable") 6 | 7 | // Address is a struct for an address 8 | type Address struct { 9 | // venue name e.g. "Brooklyn Academy of Music", and building names e.g. "Empire State Building" 10 | House string `json:"house,omitempty"` 11 | // for category queries like "restaurants", etc. 12 | Category string `json:"category,omitempty"` 13 | // phrases like "in", "near", etc. used after a category phrase to help with parsing queries like "restaurants in Brooklyn" 14 | Near string `json:"near,omitempty"` 15 | // 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. 16 | HouseNumber string `json:"house_number,omitempty"` 17 | // street name(s) 18 | Road string `json:"road,omitempty"` 19 | // an apartment, unit, office, lot, or other secondary unit designator 20 | Unit string `json:"unit,omitempty"` 21 | // expressions indicating a floor number e.g. "3rd Floor", "Ground Floor", etc. 22 | Level string `json:"level,omitempty"` 23 | // numbered/lettered staircase 24 | Staircase string `json:"staircase,omitempty"` 25 | // numbered/lettered entrance 26 | Entrance string `json:"entrance,omitempty"` 27 | // post office box: typically found in non-physical (mail-only) addresses 28 | PoBox string `json:"po_box,omitempty"` 29 | // postal codes used for mail sorting 30 | Postcode string `json:"postcode,omitempty"` 31 | // usually an unofficial neighborhood name like "Harlem", "South Bronx", or "Crown Heights" 32 | Suburb string `json:"suburb,omitempty"` 33 | // these are usually boroughs or districts within a city that serve some official purpose e.g. "Brooklyn" or "Hackney" or "Bratislava IV" 34 | CityDistrict string `json:"city_district,omitempty"` 35 | // any human settlement including cities, towns, villages, hamlets, localities, etc. 36 | City string `json:"city,omitempty"` 37 | // named islands e.g. "Maui" 38 | Island string `json:"island,omitempty"` 39 | // usually a second-level administrative division or county. 40 | StateDistrict string `json:"state_district,omitempty"` 41 | // 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.) 42 | State string `json:"state,omitempty"` 43 | // informal subdivision of a country without any political status 44 | CountryRegion string `json:"country_region,omitempty"` 45 | // sovereign nations and their dependent territories, anything with an ISO-3166 code. 46 | Country string `json:"country,omitempty"` 47 | // 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” 48 | WorldRegion string `json:"world_region,omitempty"` 49 | // Components is the raw response from libpostal 50 | Components []AddressComponent `json:"components"` 51 | } 52 | 53 | // AddressComponent is a struct for an address component 54 | type AddressComponent struct { 55 | // Label is the label of the component as defined by libpostal 56 | Label string `json:"label"` 57 | // Value is the value of the component as defined by libpostal 58 | Value string `json:"value"` 59 | } 60 | 61 | // AddressParserInput is a struct for the input to the address parser 62 | type AddressParserInput struct { 63 | // the address to parse 64 | Address string `json:"address" validate:"required"` 65 | // the language of the address. Leave empty if you don't know 66 | Language string `json:"language,omitempty"` 67 | // the country of the address. Leave empty if you don't know 68 | Country string `json:"country,omitempty"` 69 | // if true then the responses will be title Cased. Default behavior of libpostal is not to do that. 70 | TitleCase bool `json:"title_case,omitempty"` 71 | } 72 | 73 | // AddressParser is an interface for the address parser 74 | type AddressParser interface { 75 | Parse(input AddressParserInput) (Address, error) 76 | } 77 | -------------------------------------------------------------------------------- /docs/swagger.yaml: -------------------------------------------------------------------------------- 1 | basePath: / 2 | consumes: 3 | - application/json 4 | definitions: 5 | addressparser.Address: 6 | properties: 7 | category: 8 | description: for category queries like "restaurants", etc. 9 | type: string 10 | city: 11 | description: any human settlement including cities, towns, villages, hamlets, 12 | localities, etc. 13 | type: string 14 | city_district: 15 | description: these are usually boroughs or districts within a city that serve 16 | some official purpose e.g. "Brooklyn" or "Hackney" or "Bratislava IV" 17 | type: string 18 | components: 19 | description: Components is the raw response from libpostal 20 | items: 21 | $ref: '#/definitions/addressparser.AddressComponent' 22 | type: array 23 | country: 24 | description: sovereign nations and their dependent territories, anything with 25 | an ISO-3166 code. 26 | type: string 27 | country_region: 28 | description: informal subdivision of a country without any political status 29 | type: string 30 | entrance: 31 | description: numbered/lettered entrance 32 | type: string 33 | house: 34 | description: venue name e.g. "Brooklyn Academy of Music", and building names 35 | e.g. "Empire State Building" 36 | type: string 37 | house_number: 38 | description: usually refers to the external (street-facing) building number. 39 | In some countries this may be a compount, hyphenated number which also includes 40 | an apartment number, or a block number (a la Japan), but libpostal will 41 | just call it the house_number for simplicity. 42 | type: string 43 | island: 44 | description: named islands e.g. "Maui" 45 | type: string 46 | level: 47 | description: expressions indicating a floor number e.g. "3rd Floor", "Ground 48 | Floor", etc. 49 | type: string 50 | near: 51 | description: phrases like "in", "near", etc. used after a category phrase 52 | to help with parsing queries like "restaurants in Brooklyn" 53 | type: string 54 | po_box: 55 | description: 'post office box: typically found in non-physical (mail-only) 56 | addresses' 57 | type: string 58 | postcode: 59 | description: postal codes used for mail sorting 60 | type: string 61 | road: 62 | description: street name(s) 63 | type: string 64 | staircase: 65 | description: numbered/lettered staircase 66 | type: string 67 | state: 68 | description: a first-level administrative division. Scotland, Northern Ireland, 69 | Wales, and England in the UK are mapped to "state" as well (convention used 70 | in OSM, GeoPlanet, etc.) 71 | type: string 72 | state_district: 73 | description: usually a second-level administrative division or county. 74 | type: string 75 | suburb: 76 | description: usually an unofficial neighborhood name like "Harlem", "South 77 | Bronx", or "Crown Heights" 78 | type: string 79 | unit: 80 | description: an apartment, unit, office, lot, or other secondary unit designator 81 | type: string 82 | world_region: 83 | description: currently only used for appending “West Indies” after the country 84 | name, a pattern frequently used in the English-speaking Caribbean e.g. “Jamaica, 85 | West Indies” 86 | type: string 87 | type: object 88 | addressparser.AddressComponent: 89 | properties: 90 | label: 91 | description: Label is the label of the component as defined by libpostal 92 | type: string 93 | value: 94 | description: Value is the value of the component as defined by libpostal 95 | type: string 96 | type: object 97 | addressparser.AddressParserInput: 98 | properties: 99 | address: 100 | description: the address to parse 101 | type: string 102 | country: 103 | description: the country of the address. Leave empty if you don't know 104 | type: string 105 | language: 106 | description: the language of the address. Leave empty if you don't know 107 | type: string 108 | title_case: 109 | description: if true then the responses will be title Cased. Default behavior 110 | of libpostal is not to do that. 111 | type: boolean 112 | required: 113 | - address 114 | type: object 115 | web.ErrResponse: 116 | properties: 117 | code: 118 | type: integer 119 | message: 120 | type: string 121 | type: object 122 | host: localhost:8080 123 | info: 124 | contact: 125 | name: Giorgos Komninos 126 | url: http://blog.gkomninos.com 127 | description: This is the API for the address parser service 128 | title: Address Parser API 129 | version: 1.0.0 130 | paths: 131 | /parse: 132 | post: 133 | consumes: 134 | - application/json 135 | description: Parses an address into its components 136 | parameters: 137 | - description: AddressParserInput 138 | in: body 139 | name: input 140 | required: true 141 | schema: 142 | $ref: '#/definitions/addressparser.AddressParserInput' 143 | produces: 144 | - application/json 145 | responses: 146 | "200": 147 | description: OK 148 | schema: 149 | $ref: '#/definitions/addressparser.Address' 150 | "400": 151 | description: Bad Request 152 | schema: 153 | $ref: '#/definitions/web.ErrResponse' 154 | "422": 155 | description: Unprocessable Entity 156 | schema: 157 | $ref: '#/definitions/web.ErrResponse' 158 | "500": 159 | description: Internal Server Error 160 | schema: 161 | $ref: '#/definitions/web.ErrResponse' 162 | summary: Parse an address into its components 163 | tags: 164 | - AddressParser 165 | produces: 166 | - application/json 167 | swagger: "2.0" 168 | -------------------------------------------------------------------------------- /docs/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "consumes": [ 3 | "application/json" 4 | ], 5 | "produces": [ 6 | "application/json" 7 | ], 8 | "swagger": "2.0", 9 | "info": { 10 | "description": "This is the API for the address parser service", 11 | "title": "Address Parser API", 12 | "contact": { 13 | "name": "Giorgos Komninos", 14 | "url": "http://blog.gkomninos.com" 15 | }, 16 | "version": "1.0.0" 17 | }, 18 | "host": "localhost:8080", 19 | "basePath": "/", 20 | "paths": { 21 | "/parse": { 22 | "post": { 23 | "description": "Parses an address into its components", 24 | "consumes": [ 25 | "application/json" 26 | ], 27 | "produces": [ 28 | "application/json" 29 | ], 30 | "tags": [ 31 | "AddressParser" 32 | ], 33 | "summary": "Parse an address into its components", 34 | "parameters": [ 35 | { 36 | "description": "AddressParserInput", 37 | "name": "input", 38 | "in": "body", 39 | "required": true, 40 | "schema": { 41 | "$ref": "#/definitions/addressparser.AddressParserInput" 42 | } 43 | } 44 | ], 45 | "responses": { 46 | "200": { 47 | "description": "OK", 48 | "schema": { 49 | "$ref": "#/definitions/addressparser.Address" 50 | } 51 | }, 52 | "400": { 53 | "description": "Bad Request", 54 | "schema": { 55 | "$ref": "#/definitions/web.ErrResponse" 56 | } 57 | }, 58 | "422": { 59 | "description": "Unprocessable Entity", 60 | "schema": { 61 | "$ref": "#/definitions/web.ErrResponse" 62 | } 63 | }, 64 | "500": { 65 | "description": "Internal Server Error", 66 | "schema": { 67 | "$ref": "#/definitions/web.ErrResponse" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "definitions": { 75 | "addressparser.Address": { 76 | "type": "object", 77 | "properties": { 78 | "category": { 79 | "description": "for category queries like \"restaurants\", etc.", 80 | "type": "string" 81 | }, 82 | "city": { 83 | "description": "any human settlement including cities, towns, villages, hamlets, localities, etc.", 84 | "type": "string" 85 | }, 86 | "city_district": { 87 | "description": "these are usually boroughs or districts within a city that serve some official purpose e.g. \"Brooklyn\" or \"Hackney\" or \"Bratislava IV\"", 88 | "type": "string" 89 | }, 90 | "components": { 91 | "description": "Components is the raw response from libpostal", 92 | "type": "array", 93 | "items": { 94 | "$ref": "#/definitions/addressparser.AddressComponent" 95 | } 96 | }, 97 | "country": { 98 | "description": "sovereign nations and their dependent territories, anything with an ISO-3166 code.", 99 | "type": "string" 100 | }, 101 | "country_region": { 102 | "description": "informal subdivision of a country without any political status", 103 | "type": "string" 104 | }, 105 | "entrance": { 106 | "description": "numbered/lettered entrance", 107 | "type": "string" 108 | }, 109 | "house": { 110 | "description": "venue name e.g. \"Brooklyn Academy of Music\", and building names e.g. \"Empire State Building\"", 111 | "type": "string" 112 | }, 113 | "house_number": { 114 | "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.", 115 | "type": "string" 116 | }, 117 | "island": { 118 | "description": "named islands e.g. \"Maui\"", 119 | "type": "string" 120 | }, 121 | "level": { 122 | "description": "expressions indicating a floor number e.g. \"3rd Floor\", \"Ground Floor\", etc.", 123 | "type": "string" 124 | }, 125 | "near": { 126 | "description": "phrases like \"in\", \"near\", etc. used after a category phrase to help with parsing queries like \"restaurants in Brooklyn\"", 127 | "type": "string" 128 | }, 129 | "po_box": { 130 | "description": "post office box: typically found in non-physical (mail-only) addresses", 131 | "type": "string" 132 | }, 133 | "postcode": { 134 | "description": "postal codes used for mail sorting", 135 | "type": "string" 136 | }, 137 | "road": { 138 | "description": "street name(s)", 139 | "type": "string" 140 | }, 141 | "staircase": { 142 | "description": "numbered/lettered staircase", 143 | "type": "string" 144 | }, 145 | "state": { 146 | "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.)", 147 | "type": "string" 148 | }, 149 | "state_district": { 150 | "description": "usually a second-level administrative division or county.", 151 | "type": "string" 152 | }, 153 | "suburb": { 154 | "description": "usually an unofficial neighborhood name like \"Harlem\", \"South Bronx\", or \"Crown Heights\"", 155 | "type": "string" 156 | }, 157 | "unit": { 158 | "description": "an apartment, unit, office, lot, or other secondary unit designator", 159 | "type": "string" 160 | }, 161 | "world_region": { 162 | "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”", 163 | "type": "string" 164 | } 165 | } 166 | }, 167 | "addressparser.AddressComponent": { 168 | "type": "object", 169 | "properties": { 170 | "label": { 171 | "description": "Label is the label of the component as defined by libpostal", 172 | "type": "string" 173 | }, 174 | "value": { 175 | "description": "Value is the value of the component as defined by libpostal", 176 | "type": "string" 177 | } 178 | } 179 | }, 180 | "addressparser.AddressParserInput": { 181 | "type": "object", 182 | "required": [ 183 | "address" 184 | ], 185 | "properties": { 186 | "address": { 187 | "description": "the address to parse", 188 | "type": "string" 189 | }, 190 | "country": { 191 | "description": "the country of the address. Leave empty if you don't know", 192 | "type": "string" 193 | }, 194 | "language": { 195 | "description": "the language of the address. Leave empty if you don't know", 196 | "type": "string" 197 | }, 198 | "title_case": { 199 | "description": "if true then the responses will be title Cased. Default behavior of libpostal is not to do that.", 200 | "type": "boolean" 201 | } 202 | } 203 | }, 204 | "web.ErrResponse": { 205 | "type": "object", 206 | "properties": { 207 | "code": { 208 | "type": "integer" 209 | }, 210 | "message": { 211 | "type": "string" 212 | } 213 | } 214 | } 215 | } 216 | } -------------------------------------------------------------------------------- /docs/docs.go: -------------------------------------------------------------------------------- 1 | // Package docs GENERATED BY SWAG; DO NOT EDIT 2 | // This file was generated by swaggo/swag 3 | package docs 4 | 5 | import "github.com/swaggo/swag" 6 | 7 | const docTemplate = `{ 8 | "schemes": {{ marshal .Schemes }}, 9 | "consumes": [ 10 | "application/json" 11 | ], 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "swagger": "2.0", 16 | "info": { 17 | "description": "{{escape .Description}}", 18 | "title": "{{.Title}}", 19 | "contact": { 20 | "name": "Giorgos Komninos", 21 | "url": "http://blog.gkomninos.com" 22 | }, 23 | "version": "{{.Version}}" 24 | }, 25 | "host": "{{.Host}}", 26 | "basePath": "{{.BasePath}}", 27 | "paths": { 28 | "/parse": { 29 | "post": { 30 | "description": "Parses an address into its components", 31 | "consumes": [ 32 | "application/json" 33 | ], 34 | "produces": [ 35 | "application/json" 36 | ], 37 | "tags": [ 38 | "AddressParser" 39 | ], 40 | "summary": "Parse an address into its components", 41 | "parameters": [ 42 | { 43 | "description": "AddressParserInput", 44 | "name": "input", 45 | "in": "body", 46 | "required": true, 47 | "schema": { 48 | "$ref": "#/definitions/addressparser.AddressParserInput" 49 | } 50 | } 51 | ], 52 | "responses": { 53 | "200": { 54 | "description": "OK", 55 | "schema": { 56 | "$ref": "#/definitions/addressparser.Address" 57 | } 58 | }, 59 | "400": { 60 | "description": "Bad Request", 61 | "schema": { 62 | "$ref": "#/definitions/web.ErrResponse" 63 | } 64 | }, 65 | "422": { 66 | "description": "Unprocessable Entity", 67 | "schema": { 68 | "$ref": "#/definitions/web.ErrResponse" 69 | } 70 | }, 71 | "500": { 72 | "description": "Internal Server Error", 73 | "schema": { 74 | "$ref": "#/definitions/web.ErrResponse" 75 | } 76 | } 77 | } 78 | } 79 | } 80 | }, 81 | "definitions": { 82 | "addressparser.Address": { 83 | "type": "object", 84 | "properties": { 85 | "category": { 86 | "description": "for category queries like \"restaurants\", etc.", 87 | "type": "string" 88 | }, 89 | "city": { 90 | "description": "any human settlement including cities, towns, villages, hamlets, localities, etc.", 91 | "type": "string" 92 | }, 93 | "city_district": { 94 | "description": "these are usually boroughs or districts within a city that serve some official purpose e.g. \"Brooklyn\" or \"Hackney\" or \"Bratislava IV\"", 95 | "type": "string" 96 | }, 97 | "components": { 98 | "description": "Components is the raw response from libpostal", 99 | "type": "array", 100 | "items": { 101 | "$ref": "#/definitions/addressparser.AddressComponent" 102 | } 103 | }, 104 | "country": { 105 | "description": "sovereign nations and their dependent territories, anything with an ISO-3166 code.", 106 | "type": "string" 107 | }, 108 | "country_region": { 109 | "description": "informal subdivision of a country without any political status", 110 | "type": "string" 111 | }, 112 | "entrance": { 113 | "description": "numbered/lettered entrance", 114 | "type": "string" 115 | }, 116 | "house": { 117 | "description": "venue name e.g. \"Brooklyn Academy of Music\", and building names e.g. \"Empire State Building\"", 118 | "type": "string" 119 | }, 120 | "house_number": { 121 | "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.", 122 | "type": "string" 123 | }, 124 | "island": { 125 | "description": "named islands e.g. \"Maui\"", 126 | "type": "string" 127 | }, 128 | "level": { 129 | "description": "expressions indicating a floor number e.g. \"3rd Floor\", \"Ground Floor\", etc.", 130 | "type": "string" 131 | }, 132 | "near": { 133 | "description": "phrases like \"in\", \"near\", etc. used after a category phrase to help with parsing queries like \"restaurants in Brooklyn\"", 134 | "type": "string" 135 | }, 136 | "po_box": { 137 | "description": "post office box: typically found in non-physical (mail-only) addresses", 138 | "type": "string" 139 | }, 140 | "postcode": { 141 | "description": "postal codes used for mail sorting", 142 | "type": "string" 143 | }, 144 | "road": { 145 | "description": "street name(s)", 146 | "type": "string" 147 | }, 148 | "staircase": { 149 | "description": "numbered/lettered staircase", 150 | "type": "string" 151 | }, 152 | "state": { 153 | "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.)", 154 | "type": "string" 155 | }, 156 | "state_district": { 157 | "description": "usually a second-level administrative division or county.", 158 | "type": "string" 159 | }, 160 | "suburb": { 161 | "description": "usually an unofficial neighborhood name like \"Harlem\", \"South Bronx\", or \"Crown Heights\"", 162 | "type": "string" 163 | }, 164 | "unit": { 165 | "description": "an apartment, unit, office, lot, or other secondary unit designator", 166 | "type": "string" 167 | }, 168 | "world_region": { 169 | "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”", 170 | "type": "string" 171 | } 172 | } 173 | }, 174 | "addressparser.AddressComponent": { 175 | "type": "object", 176 | "properties": { 177 | "label": { 178 | "description": "Label is the label of the component as defined by libpostal", 179 | "type": "string" 180 | }, 181 | "value": { 182 | "description": "Value is the value of the component as defined by libpostal", 183 | "type": "string" 184 | } 185 | } 186 | }, 187 | "addressparser.AddressParserInput": { 188 | "type": "object", 189 | "required": [ 190 | "address" 191 | ], 192 | "properties": { 193 | "address": { 194 | "description": "the address to parse", 195 | "type": "string" 196 | }, 197 | "country": { 198 | "description": "the country of the address. Leave empty if you don't know", 199 | "type": "string" 200 | }, 201 | "language": { 202 | "description": "the language of the address. Leave empty if you don't know", 203 | "type": "string" 204 | }, 205 | "title_case": { 206 | "description": "if true then the responses will be title Cased. Default behavior of libpostal is not to do that.", 207 | "type": "boolean" 208 | } 209 | } 210 | }, 211 | "web.ErrResponse": { 212 | "type": "object", 213 | "properties": { 214 | "code": { 215 | "type": "integer" 216 | }, 217 | "message": { 218 | "type": "string" 219 | } 220 | } 221 | } 222 | } 223 | }` 224 | 225 | // SwaggerInfo holds exported Swagger Info so clients can modify it 226 | var SwaggerInfo = &swag.Spec{ 227 | Version: "1.0.0", 228 | Host: "localhost:8080", 229 | BasePath: "/", 230 | Schemes: []string{}, 231 | Title: "Address Parser API", 232 | Description: "This is the API for the address parser service", 233 | InfoInstanceName: "swagger", 234 | SwaggerTemplate: docTemplate, 235 | } 236 | 237 | func init() { 238 | swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) 239 | } 240 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= 2 | github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= 3 | github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= 4 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 5 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= 6 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 7 | github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 8 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= 13 | github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 14 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 15 | github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= 16 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 17 | github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= 18 | github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= 19 | github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= 20 | github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= 21 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 22 | github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= 23 | github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= 24 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 25 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 26 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 27 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 28 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 29 | github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= 30 | github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= 31 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 32 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 33 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 34 | github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a h1:5tcB33GTXm0pFUiEFpmE91tMsHQj+I+W7zubT8J/ugI= 35 | github.com/gosom/kit v0.0.0-20230309082109-543b32ac686a/go.mod h1:ngnWSsuBEpCA5Y43kZRa3x8RBYZZ4LDtvZHO4N5dHZ0= 36 | github.com/ismurov/swaggerui v0.2.0 h1:rx/BTbufsCUMq0G2a0Cmd045nkrRmHBa7T249wqnVBM= 37 | github.com/ismurov/swaggerui v0.2.0/go.mod h1:EaaariTC2xXLMsKU9v3MdYT62/akXBvRFxmuY9zyqF0= 38 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 39 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 40 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 41 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 42 | github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= 43 | github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 44 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 45 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 46 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 47 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 48 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 49 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 50 | github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= 51 | github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= 52 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 53 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 54 | github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= 55 | github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 56 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 57 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 58 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 59 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 60 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 61 | github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= 62 | github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 63 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 64 | github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= 65 | github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= 66 | github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d h1:KJ+N55d9zLN8fTg3NchLdmmAmPieXC5E6UNJ8zFFttU= 67 | github.com/openvenues/gopostal v0.0.0-20171226154602-e0184512a45d/go.mod h1:Ycrd7XnwQdumHzpB/6WEa85B4WNdbLC6Wz4FAQNkaV0= 68 | github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= 69 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 70 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 71 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 72 | github.com/realclientip/realclientip-go v1.0.0 h1:+yPxeC0mEaJzq1BfCt2h4BxlyrvIIBzR6suDc3BEF1U= 73 | github.com/realclientip/realclientip-go v1.0.0/go.mod h1:CXnUdVwFRcXFJIRb/dTYqbT7ud48+Pi2pFm80bxDmcI= 74 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= 75 | github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= 76 | github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 77 | github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= 78 | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 79 | github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= 80 | github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= 81 | github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= 82 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 83 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 84 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 85 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 86 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 87 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 88 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 89 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 90 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 91 | github.com/swaggo/swag v1.8.10 h1:eExW4bFa52WOjqRzRD58bgWsWfdFJso50lpbeTcmTfo= 92 | github.com/swaggo/swag v1.8.10/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= 93 | github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I= 94 | github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ= 95 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 96 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 97 | golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= 98 | golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= 99 | golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= 100 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 101 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 102 | golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 107 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 109 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 110 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 111 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 112 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 113 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 114 | golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= 115 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 116 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 117 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 118 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 119 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 120 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 121 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 122 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 123 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 124 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 125 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 126 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 127 | --------------------------------------------------------------------------------