From 8cd3957c9ef03c506b7c2a9e943d94288e7acd83 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Tue, 23 Aug 2022 22:31:53 -0300 Subject: [PATCH 01/20] feat: starting prototyping new arch --- cmd/main.go | 16 ++++++ internal/entity/cep.go | 35 +++++++++++++ internal/service/brasilapi/brasilapi_impl.go | 51 +++++++++++++++++++ internal/service/brasilapi/brasilapi_model.go | 10 ++++ {services => internal/service}/container.go | 0 {services => internal/service}/correios.go | 0 {services => internal/service}/viacep.go | 0 {services => internal/service}/widenet.go | 0 lagoinha.go | 21 +++++--- pkg/errors/cep.go | 11 ++++ pkg/errors/standard.go | 15 ++++++ pkg/validator/cep.go | 35 +++++++++++++ 12 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 cmd/main.go create mode 100644 internal/entity/cep.go create mode 100644 internal/service/brasilapi/brasilapi_impl.go create mode 100644 internal/service/brasilapi/brasilapi_model.go rename {services => internal/service}/container.go (100%) rename {services => internal/service}/correios.go (100%) rename {services => internal/service}/viacep.go (100%) rename {services => internal/service}/widenet.go (100%) create mode 100644 pkg/errors/cep.go create mode 100644 pkg/errors/standard.go create mode 100644 pkg/validator/cep.go diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..cbb8aae --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "log" + + "github.com/igorhalfeld/lagoinha" +) + +func main() { + address, err := lagoinha.GetAddress("01310200") + if err != nil { + log.Fatalf("\nError %v:", err) + } + + log.Printf("Complete Address %v:", address) +} diff --git a/internal/entity/cep.go b/internal/entity/cep.go new file mode 100644 index 0000000..38f8202 --- /dev/null +++ b/internal/entity/cep.go @@ -0,0 +1,35 @@ +package entity + +import "github.com/igorhalfeld/lagoinha/pkg/validator" + +// Cep standard cep struct +type Cep struct { + Cep string `json:"cep"` + Street string `json:"street"` + Neighborhood string `json:"neighborhood"` + City string `json:"city"` + State string `json:"state"` + Provider string `json:"provider"` +} + +func (c *Cep) ApplyFormaterAndLinters() { + c.Cep = validator.RemoveSpecialCharacters(c.Cep) + c.Cep = validator.LeftPadWithZeros(c.Cep) +} + +func (c *Cep) IsValid() bool { + return validator.ValidateInputLength(c.Cep) +} + +func (c *Cep) HasAllAddressInfo() bool { + if c.Cep != "" && + c.Street != "" && + c.Neighborhood != "" && + c.City != "" && + c.State != "" && + c.Provider != "" { + return true + } + + return false +} diff --git a/internal/service/brasilapi/brasilapi_impl.go b/internal/service/brasilapi/brasilapi_impl.go new file mode 100644 index 0000000..964522a --- /dev/null +++ b/internal/service/brasilapi/brasilapi_impl.go @@ -0,0 +1,51 @@ +package brasilapi + +import ( + "encoding/json" + "errors" + "net/http" + + "github.com/igorhalfeld/lagoinha/internal/entity" +) + +type BrasilAPI struct { +} + +func New() BrasilAPI { + return &BrasilAPI{} +} + +func (ba *BrasilAPI) Request(cep string) (*entity.Cep, error) { + result := BrasilAPIResponse{} + + res, err := http.Get("https://brasilapi.com.br/api/cep/v1/" + cep) + if err != nil { + return nil, err + } + + defer res.Body.Close() + + err = json.NewDecoder(res.Body).Decode(&result) + if err != nil { + return nil, err + } + + return vc.formater(&result) +} + +func (ba *BrasilAPI) formater(r *BrasilAPIResponse) (*entity.Cep, error) { + if r == nil { + return nil, errors.CepNotFoundError + } + + cep := &entity.Cep{ + Cep: r.Cep, + City: r.City, + Neighborhood: r.Neighborhood, + State: r.State, + Street: r.Street, + Provider: "BrasilAPI", + } + + return cep, nil +} diff --git a/internal/service/brasilapi/brasilapi_model.go b/internal/service/brasilapi/brasilapi_model.go new file mode 100644 index 0000000..a3431b2 --- /dev/null +++ b/internal/service/brasilapi/brasilapi_model.go @@ -0,0 +1,10 @@ +package brasilapi + +type BrasilAPIResponse struct { + Cep string `json:"cep"` + State string `json:"state"` + City string `json:"city"` + Neighborhood string `json:"neighborhood"` + Street string `json:"street"` + Service string `json:"service"` +} diff --git a/services/container.go b/internal/service/container.go similarity index 100% rename from services/container.go rename to internal/service/container.go diff --git a/services/correios.go b/internal/service/correios.go similarity index 100% rename from services/correios.go rename to internal/service/correios.go diff --git a/services/viacep.go b/internal/service/viacep.go similarity index 100% rename from services/viacep.go rename to internal/service/viacep.go diff --git a/services/widenet.go b/internal/service/widenet.go similarity index 100% rename from services/widenet.go rename to internal/service/widenet.go diff --git a/lagoinha.go b/lagoinha.go index c81105f..7b27cb7 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -3,23 +3,28 @@ package lagoinha import ( "reflect" + "github.com/igorhalfeld/lagoinha/internal/entity" "github.com/igorhalfeld/lagoinha/services" - "github.com/igorhalfeld/lagoinha/structs" - "github.com/igorhalfeld/lagoinha/utils" ) // GetAddress - get address -func GetAddress(cep string) (*structs.Cep, error) { +func GetAddress(cepRaw string) (*entity.Cep, error) { + cep := entity.Cep{ + Cep: cepRaw, + } + cep.ApplyFormaterAndLinters() + + if !cep.IsValid() { + return nil, CepNotValidError + } + services := services.Container{ CorreiosService: services.NewCorreiosService(), ViaCepService: services.NewViaCepService(), WidenetService: services.NewWidenetService(), } - cepValidated := utils.RemoveSpecialCharacters(cep) - cepValidated = utils.LeftPadWithZeros(cep) - - respCh := make(chan *structs.Cep) + respCh := make(chan *entity.Cep) errCh := make(chan error) var servicesCount int = reflect.TypeOf(services).NumField() @@ -40,7 +45,7 @@ func GetAddress(cep string) (*structs.Cep, error) { respCh <- c errCh <- nil } - }(cepValidated) + }(cep.Cep) go func(cv string) { c, err := services.ViaCepService.Request(cv) diff --git a/pkg/errors/cep.go b/pkg/errors/cep.go new file mode 100644 index 0000000..f4318a5 --- /dev/null +++ b/pkg/errors/cep.go @@ -0,0 +1,11 @@ +package errors + +var CepNotFoundError error = LagoinhaError{ + Type: ApplicationError, + Message: "cep not found", +} + +var CepNotValidError error = LagoinhaError{ + Type: ValidationError, + Message: "cep not valid", +} diff --git a/pkg/errors/standard.go b/pkg/errors/standard.go new file mode 100644 index 0000000..892aaa7 --- /dev/null +++ b/pkg/errors/standard.go @@ -0,0 +1,15 @@ +package errors + +import "fmt" + +var ValidationError string = "validation_error" +var ApplicationError string = "application_error" + +type LagoinhaError struct { + Message string + Type string +} + +func (l *LagoinhaError) Error() string { + return fmt.Sprintf("%s - %s", l.Type, l.Message) +} diff --git a/pkg/validator/cep.go b/pkg/validator/cep.go new file mode 100644 index 0000000..882d037 --- /dev/null +++ b/pkg/validator/cep.go @@ -0,0 +1,35 @@ +package validator + +import ( + "regexp" + "strings" +) + +// ValidateInputLength validate input length +func ValidateInputLength(cepRaw string) (status bool) { + const cepSize = 8 + cepLength := len(cepRaw) + if cepLength <= cepSize { + status = true + } else { + status = false + } + return status +} + +// RemoveSpecialCharacters remove special characters +func RemoveSpecialCharacters(cepRaw string) (cepParsed string) { + rule := regexp.MustCompile(`\D+`) + cepParsed = rule.ReplaceAllString(cepRaw, "") + return cepParsed +} + +// LeftPadWithZeros pad cep with zeros +func LeftPadWithZeros(cepRaw string) (cepParsed string) { + const cepSize = 8 + cepLength := len(cepRaw) + timesToRepeat := cepSize - cepLength + pad := strings.Repeat("0", timesToRepeat) + cepParsed = pad + cepRaw + return cepParsed +} From ee4267e7ca6ef992cc99df08b04e85b3a52051fc Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 01:00:49 -0300 Subject: [PATCH 02/20] chore: move service to folder structure --- internal/service/brasilapi/brasilapi_impl.go | 4 ++-- internal/service/brasilapi/brasilapi_model.go | 2 +- internal/service/container.go | 8 -------- .../coorreios_impl.go} | 18 ++++++------------ internal/service/correios/correios_model.go | 17 +++++++++++++++++ .../{viacep.go => viacep/viacep_impl.go} | 15 +++++---------- internal/service/viacep/viacep_model.go | 9 +++++++++ internal/service/{ => widenet}/widenet.go | 14 +++++--------- internal/service/widenet/widenet_model.go | 9 +++++++++ 9 files changed, 54 insertions(+), 42 deletions(-) delete mode 100644 internal/service/container.go rename internal/service/{correios.go => correios/coorreios_impl.go} (76%) create mode 100644 internal/service/correios/correios_model.go rename internal/service/{viacep.go => viacep/viacep_impl.go} (69%) create mode 100644 internal/service/viacep/viacep_model.go rename internal/service/{ => widenet}/widenet.go (70%) create mode 100644 internal/service/widenet/widenet_model.go diff --git a/internal/service/brasilapi/brasilapi_impl.go b/internal/service/brasilapi/brasilapi_impl.go index 964522a..2a2b59f 100644 --- a/internal/service/brasilapi/brasilapi_impl.go +++ b/internal/service/brasilapi/brasilapi_impl.go @@ -8,7 +8,7 @@ import ( "github.com/igorhalfeld/lagoinha/internal/entity" ) -type BrasilAPI struct { +type BrasilAPIService struct { } func New() BrasilAPI { @@ -16,7 +16,7 @@ func New() BrasilAPI { } func (ba *BrasilAPI) Request(cep string) (*entity.Cep, error) { - result := BrasilAPIResponse{} + result := brasilAPIResponse{} res, err := http.Get("https://brasilapi.com.br/api/cep/v1/" + cep) if err != nil { diff --git a/internal/service/brasilapi/brasilapi_model.go b/internal/service/brasilapi/brasilapi_model.go index a3431b2..f698a2c 100644 --- a/internal/service/brasilapi/brasilapi_model.go +++ b/internal/service/brasilapi/brasilapi_model.go @@ -1,6 +1,6 @@ package brasilapi -type BrasilAPIResponse struct { +type brasilAPIResponse struct { Cep string `json:"cep"` State string `json:"state"` City string `json:"city"` diff --git a/internal/service/container.go b/internal/service/container.go deleted file mode 100644 index 84147a0..0000000 --- a/internal/service/container.go +++ /dev/null @@ -1,8 +0,0 @@ -package services - -// Container for services -type Container struct { - CorreiosService CorreiosService - ViaCepService ViaCepService - WidenetService WidenetService -} diff --git a/internal/service/correios.go b/internal/service/correios/coorreios_impl.go similarity index 76% rename from internal/service/correios.go rename to internal/service/correios/coorreios_impl.go index 25b1917..5080b2c 100644 --- a/internal/service/correios.go +++ b/internal/service/correios/coorreios_impl.go @@ -1,4 +1,4 @@ -package services +package correios import ( "bytes" @@ -9,24 +9,18 @@ import ( "github.com/igorhalfeld/lagoinha/structs" ) -// CorreiosService service -type CorreiosService interface { - Request(cep string) (*structs.Cep, error) -} - -type correiosImpl struct{} +type CorreiosService struct{} -// NewCorreiosService creates a new instance -func NewCorreiosService() CorreiosService { +func New() CorreiosService { return &correiosImpl{} } // Request - fetch data from correios api -func (cs *correiosImpl) Request(cep string) (*structs.Cep, error) { +func (cs *CorreiosService) Request(cep string) (*structs.Cep, error) { const proxyURL = "https://proxier.now.sh/" client := &http.Client{} - result := structs.CorreiosResponse{} + result := correiosResponse{} url := proxyURL + "https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente?wsdl" payload := ` @@ -62,7 +56,7 @@ func (cs *correiosImpl) Request(cep string) (*structs.Cep, error) { return cs.formater(&result) } -func (cs *correiosImpl) formater(r *structs.CorreiosResponse) (*structs.Cep, error) { +func (cs *CorreiosService) formater(r *structs.CorreiosResponse) (*structs.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } diff --git a/internal/service/correios/correios_model.go b/internal/service/correios/correios_model.go new file mode 100644 index 0000000..e6df903 --- /dev/null +++ b/internal/service/correios/correios_model.go @@ -0,0 +1,17 @@ +package correios + +type correiosBody struct { + Return struct { + Cep string `xml:"cep"` + State string `xml:"uf"` + City string `xml:"cidade"` + Neighborhood string `xml:"bairro"` + Street string `xml:"end"` + } `xml:"return"` +} + +type correiosResponse struct { + Body struct { + Consult correiosBody `xml:"consultaCEPResponse"` + } `xml:"Body"` +} diff --git a/internal/service/viacep.go b/internal/service/viacep/viacep_impl.go similarity index 69% rename from internal/service/viacep.go rename to internal/service/viacep/viacep_impl.go index e71f993..b2d00fb 100644 --- a/internal/service/viacep.go +++ b/internal/service/viacep/viacep_impl.go @@ -1,4 +1,4 @@ -package services +package viacep import ( "encoding/json" @@ -8,12 +8,7 @@ import ( "github.com/igorhalfeld/lagoinha/structs" ) -// ViaCepService service -type ViaCepService interface { - Request(cep string) (*structs.Cep, error) -} - -type viaCepImpl struct { +type ViaCepService struct { } // NewViaCepService creates a new instance @@ -22,8 +17,8 @@ func NewViaCepService() ViaCepService { } // Request - fetch data from viacep api -func (vc *viaCepImpl) Request(cep string) (*structs.Cep, error) { - result := structs.ViaCepResponse{} +func (vc *ViaCepService) Request(cep string) (*structs.Cep, error) { + result := viaCepResponse{} res, err := http.Get("https://viacep.com.br/ws/" + cep + "/json/") if err != nil { @@ -40,7 +35,7 @@ func (vc *viaCepImpl) Request(cep string) (*structs.Cep, error) { return vc.formater(&result) } -func (vc *viaCepImpl) formater(r *structs.ViaCepResponse) (*structs.Cep, error) { +func (vc *ViaCepService) formater(r *structs.ViaCepResponse) (*structs.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } diff --git a/internal/service/viacep/viacep_model.go b/internal/service/viacep/viacep_model.go new file mode 100644 index 0000000..515c99d --- /dev/null +++ b/internal/service/viacep/viacep_model.go @@ -0,0 +1,9 @@ +package viacep + +type viaCepResponse struct { + Cep string `json:"cep"` + State string `json:"uf"` + City string `json:"localidade"` + Neighborhood string `json:"bairro"` + Street string `json:"logradouro"` +} diff --git a/internal/service/widenet.go b/internal/service/widenet/widenet.go similarity index 70% rename from internal/service/widenet.go rename to internal/service/widenet/widenet.go index 6b4c0b9..8d6d37d 100644 --- a/internal/service/widenet.go +++ b/internal/service/widenet/widenet.go @@ -1,4 +1,4 @@ -package services +package widenet import ( "encoding/json" @@ -8,11 +8,7 @@ import ( "github.com/igorhalfeld/lagoinha/structs" ) -// ViaCepService service -type WidenetService interface { - Request(cep string) (*structs.Cep, error) -} -type widenetImpl struct{} +type WidenetService struct{} // NewViaCepService creates a new instance func NewWidenetService() WidenetService { @@ -20,8 +16,8 @@ func NewWidenetService() WidenetService { } // Request - fetch data from viacep api -func (wn *widenetImpl) Request(cep string) (*structs.Cep, error) { - result := structs.WidenetResponse{} +func (wn *WidenetService) Request(cep string) (*structs.Cep, error) { + result := widenetResponse{} res, err := http.Get("http://apps.widenet.com.br/busca-cep/api/cep/" + cep + ".json") if err != nil { @@ -38,7 +34,7 @@ func (wn *widenetImpl) Request(cep string) (*structs.Cep, error) { return wn.formater(&result) } -func (wn *widenetImpl) formater(r *structs.WidenetResponse) (*structs.Cep, error) { +func (wn *WidenetService) formater(r *structs.WidenetResponse) (*structs.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } diff --git a/internal/service/widenet/widenet_model.go b/internal/service/widenet/widenet_model.go new file mode 100644 index 0000000..c028328 --- /dev/null +++ b/internal/service/widenet/widenet_model.go @@ -0,0 +1,9 @@ +package widenet + +type widenetResponse struct { + Cep string `json:"code"` + State string `json:"state"` + City string `json:"city"` + Neighborhood string `json:"district"` + Street string `json:"address"` +} From f1336c0d48f7607ac2c8f12df7294dd345f82ce9 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 01:06:10 -0300 Subject: [PATCH 03/20] chore: move function to other place --- pkg/errors/cep.go | 4 ++-- pkg/formater/cep.go | 21 +++++++++++++++++++++ pkg/validator/cep.go | 29 +++-------------------------- 3 files changed, 26 insertions(+), 28 deletions(-) create mode 100644 pkg/formater/cep.go diff --git a/pkg/errors/cep.go b/pkg/errors/cep.go index f4318a5..f7d3dcc 100644 --- a/pkg/errors/cep.go +++ b/pkg/errors/cep.go @@ -1,11 +1,11 @@ package errors -var CepNotFoundError error = LagoinhaError{ +var CepNotFoundError error = &LagoinhaError{ Type: ApplicationError, Message: "cep not found", } -var CepNotValidError error = LagoinhaError{ +var CepNotValidError error = &LagoinhaError{ Type: ValidationError, Message: "cep not valid", } diff --git a/pkg/formater/cep.go b/pkg/formater/cep.go new file mode 100644 index 0000000..5470d31 --- /dev/null +++ b/pkg/formater/cep.go @@ -0,0 +1,21 @@ +package formater + +import ( + "regexp" + "strings" +) + +func RemoveSpecialCharacters(cepRaw string) (cepParsed string) { + rule := regexp.MustCompile(`\D+`) + cepParsed = rule.ReplaceAllString(cepRaw, "") + return cepParsed +} + +func LeftPadWithZeros(cepRaw string) (cepParsed string) { + const cepSize = 8 + cepLength := len(cepRaw) + timesToRepeat := cepSize - cepLength + pad := strings.Repeat("0", timesToRepeat) + cepParsed = pad + cepRaw + return cepParsed +} diff --git a/pkg/validator/cep.go b/pkg/validator/cep.go index 882d037..d5e44e3 100644 --- a/pkg/validator/cep.go +++ b/pkg/validator/cep.go @@ -1,35 +1,12 @@ package validator -import ( - "regexp" - "strings" -) - -// ValidateInputLength validate input length -func ValidateInputLength(cepRaw string) (status bool) { +func ExceedsCepMaximumSize(cepRaw string) (status bool) { const cepSize = 8 cepLength := len(cepRaw) if cepLength <= cepSize { - status = true - } else { status = false + } else { + status = true } return status } - -// RemoveSpecialCharacters remove special characters -func RemoveSpecialCharacters(cepRaw string) (cepParsed string) { - rule := regexp.MustCompile(`\D+`) - cepParsed = rule.ReplaceAllString(cepRaw, "") - return cepParsed -} - -// LeftPadWithZeros pad cep with zeros -func LeftPadWithZeros(cepRaw string) (cepParsed string) { - const cepSize = 8 - cepLength := len(cepRaw) - timesToRepeat := cepSize - cepLength - pad := strings.Repeat("0", timesToRepeat) - cepParsed = pad + cepRaw - return cepParsed -} From 62228463604b8d33b1647be33e24dd7cd198b3c6 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 01:06:30 -0300 Subject: [PATCH 04/20] fix: cep isValid logic --- internal/entity/cep.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/internal/entity/cep.go b/internal/entity/cep.go index 38f8202..fe6e309 100644 --- a/internal/entity/cep.go +++ b/internal/entity/cep.go @@ -1,6 +1,9 @@ package entity -import "github.com/igorhalfeld/lagoinha/pkg/validator" +import ( + "github.com/igorhalfeld/lagoinha/pkg/formater" + "github.com/igorhalfeld/lagoinha/pkg/validator" +) // Cep standard cep struct type Cep struct { @@ -12,13 +15,16 @@ type Cep struct { Provider string `json:"provider"` } -func (c *Cep) ApplyFormaterAndLinters() { - c.Cep = validator.RemoveSpecialCharacters(c.Cep) - c.Cep = validator.LeftPadWithZeros(c.Cep) -} - func (c *Cep) IsValid() bool { - return validator.ValidateInputLength(c.Cep) + c.Cep = formater.RemoveSpecialCharacters(c.Cep) + + if c.Cep == "" || validator.ExceedsCepMaximumSize(c.Cep) { + return false + } + + c.Cep = formater.LeftPadWithZeros(c.Cep) + + return true } func (c *Cep) HasAllAddressInfo() bool { From eaf4dcdbdb7169e529d67e21103e591e84072c48 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 01:06:59 -0300 Subject: [PATCH 05/20] chore: change the GetAddress signature --- Makefile | 3 +++ cmd/main.go | 14 +++++----- lagoinha.go | 76 +++++++++-------------------------------------------- 3 files changed, 23 insertions(+), 70 deletions(-) diff --git a/Makefile b/Makefile index e6f9cab..0b9a9b4 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +run-example: + go run cmd/main.go + test: APP_ENV=testing CONFIG_DIR=${PWD} go test -v -cover -count 1 -failfast ./... diff --git a/cmd/main.go b/cmd/main.go index cbb8aae..534405d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,16 +1,18 @@ package main import ( - "log" + "fmt" "github.com/igorhalfeld/lagoinha" ) func main() { - address, err := lagoinha.GetAddress("01310200") - if err != nil { - log.Fatalf("\nError %v:", err) - } + chResp, chErr := lagoinha.GetAddress("") - log.Printf("Complete Address %v:", address) + select { + case address := <-chResp: + fmt.Printf("Response: %+v\n", address) + case err := <-chErr: + fmt.Printf("Response: %+v\n", err) + } } diff --git a/lagoinha.go b/lagoinha.go index 7b27cb7..e26f0e6 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -1,81 +1,29 @@ package lagoinha import ( - "reflect" - "github.com/igorhalfeld/lagoinha/internal/entity" - "github.com/igorhalfeld/lagoinha/services" + "github.com/igorhalfeld/lagoinha/pkg/errors" ) -// GetAddress - get address -func GetAddress(cepRaw string) (*entity.Cep, error) { +func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) { cep := entity.Cep{ Cep: cepRaw, } - cep.ApplyFormaterAndLinters() if !cep.IsValid() { - return nil, CepNotValidError - } - - services := services.Container{ - CorreiosService: services.NewCorreiosService(), - ViaCepService: services.NewViaCepService(), - WidenetService: services.NewWidenetService(), + chError <- errors.CepNotValidError + return } - respCh := make(chan *entity.Cep) - errCh := make(chan error) - - var servicesCount int = reflect.TypeOf(services).NumField() - var errorsCount []error - - // @TODO: If services be more than 3, - // dispatch this goroutines dynamically - go func(cv string) { - c, err := services.CorreiosService.Request(cv) - if err != nil { - errorsCount = append(errorsCount, err) - if len(errorsCount) == servicesCount { - errCh <- err - respCh <- nil - } - } - if c != nil { - respCh <- c - errCh <- nil - } - }(cep.Cep) + chResponse <- &cep +} - go func(cv string) { - c, err := services.ViaCepService.Request(cv) - if err != nil { - errorsCount = append(errorsCount, err) - if len(errorsCount) == servicesCount { - errCh <- err - respCh <- nil - } - } - if c != nil { - respCh <- c - errCh <- nil - } - }(cepValidated) +// GetAddress - get address +func GetAddress(cepRaw string) (chan *entity.Cep, chan error) { + chResponse := make(chan *entity.Cep) + chError := make(chan error) - go func(cv string) { - c, err := services.WidenetService.Request(cv) - if err != nil { - errorsCount = append(errorsCount, err) - if len(errorsCount) == servicesCount { - errCh <- err - respCh <- nil - } - } - if c != nil { - respCh <- c - errCh <- nil - } - }(cepValidated) + go getAddress(cepRaw, chResponse, chError) - return <-respCh, <-errCh + return chResponse, chError } From 06b729b51440d431a32db8e1314a656c17074fba Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 01:14:57 -0300 Subject: [PATCH 06/20] chore: remove unnecessary folders and files --- examples/app.go | 16 ---------------- structs/cep.go | 11 ----------- structs/response.go | 42 ------------------------------------------ utils/cep.go | 35 ----------------------------------- 4 files changed, 104 deletions(-) delete mode 100644 examples/app.go delete mode 100644 structs/cep.go delete mode 100644 structs/response.go delete mode 100644 utils/cep.go diff --git a/examples/app.go b/examples/app.go deleted file mode 100644 index cbb8aae..0000000 --- a/examples/app.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "log" - - "github.com/igorhalfeld/lagoinha" -) - -func main() { - address, err := lagoinha.GetAddress("01310200") - if err != nil { - log.Fatalf("\nError %v:", err) - } - - log.Printf("Complete Address %v:", address) -} diff --git a/structs/cep.go b/structs/cep.go deleted file mode 100644 index b2cdeb0..0000000 --- a/structs/cep.go +++ /dev/null @@ -1,11 +0,0 @@ -package structs - -// Cep standard cep struct -type Cep struct { - Cep string `json:"cep"` - Street string `json:"street"` - Neighborhood string `json:"neighborhood"` - City string `json:"city"` - State string `json:"state"` - Provider string `json:"provider"` -} diff --git a/structs/response.go b/structs/response.go deleted file mode 100644 index bce41ff..0000000 --- a/structs/response.go +++ /dev/null @@ -1,42 +0,0 @@ -package structs - -// Response standard response struct -type Response struct { - Data Cep - Err error -} - -// ViaCepResponse Via cep response -type ViaCepResponse struct { - Cep string `json:"cep"` - State string `json:"uf"` - City string `json:"localidade"` - Neighborhood string `json:"bairro"` - Street string `json:"logradouro"` -} - -// WidenetResponse Widenet response -type WidenetResponse struct { - Cep string `json:"code"` - State string `json:"state"` - City string `json:"city"` - Neighborhood string `json:"district"` - Street string `json:"address"` -} - -// CorreiosResponse Correios response -type CorreiosResponse struct { - Body struct { - Consult correiosBody `xml:"consultaCEPResponse"` - } `xml:"Body"` -} - -type correiosBody struct { - Return struct { - Cep string `xml:"cep"` - State string `xml:"uf"` - City string `xml:"cidade"` - Neighborhood string `xml:"bairro"` - Street string `xml:"end"` - } `xml:"return"` -} diff --git a/utils/cep.go b/utils/cep.go deleted file mode 100644 index f4559ea..0000000 --- a/utils/cep.go +++ /dev/null @@ -1,35 +0,0 @@ -package utils - -import ( - "regexp" - "strings" -) - -// ValidateInputLength Validate input length -func ValidateInputLength(cepRaw string) (status bool) { - const cepSize = 8 - cepLength := len(cepRaw) - if cepLength <= cepSize { - status = true - } else { - status = false - } - return status -} - -// RemoveSpecialCharacters Remove special characters -func RemoveSpecialCharacters(cepRaw string) (cepParsed string) { - rule := regexp.MustCompile(`\D+`) - cepParsed = rule.ReplaceAllString(cepRaw, "") - return cepParsed -} - -// LeftPadWithZeros Pad cep with zeros -func LeftPadWithZeros(cepRaw string) (cepParsed string) { - const cepSize = 8 - cepLength := len(cepRaw) - timesToRepeat := cepSize - cepLength - pad := strings.Repeat("0", timesToRepeat) - cepParsed = pad + cepRaw - return cepParsed -} From bc37068346affd953936de76a7984a33e400ae44 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 15:02:19 -0300 Subject: [PATCH 07/20] chore: add first provider --- cmd/main.go | 2 +- internal/service/correios/coorreios_impl.go | 2 +- internal/service/viacep/viacep_impl.go | 12 ++++++------ lagoinha.go | 12 +++++++++++- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 534405d..2ce09f7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,7 +7,7 @@ import ( ) func main() { - chResp, chErr := lagoinha.GetAddress("") + chResp, chErr := lagoinha.GetAddress("04568000") select { case address := <-chResp: diff --git a/internal/service/correios/coorreios_impl.go b/internal/service/correios/coorreios_impl.go index 5080b2c..3ab16fe 100644 --- a/internal/service/correios/coorreios_impl.go +++ b/internal/service/correios/coorreios_impl.go @@ -12,7 +12,7 @@ import ( type CorreiosService struct{} func New() CorreiosService { - return &correiosImpl{} + return &CorreiosService{} } // Request - fetch data from correios api diff --git a/internal/service/viacep/viacep_impl.go b/internal/service/viacep/viacep_impl.go index b2d00fb..9791ec5 100644 --- a/internal/service/viacep/viacep_impl.go +++ b/internal/service/viacep/viacep_impl.go @@ -5,19 +5,19 @@ import ( "errors" "net/http" - "github.com/igorhalfeld/lagoinha/structs" + "github.com/igorhalfeld/lagoinha/internal/entity" ) type ViaCepService struct { } // NewViaCepService creates a new instance -func NewViaCepService() ViaCepService { - return &viaCepImpl{} +func New() *ViaCepService { + return &ViaCepService{} } // Request - fetch data from viacep api -func (vc *ViaCepService) Request(cep string) (*structs.Cep, error) { +func (vc *ViaCepService) Request(cep string) (*entity.Cep, error) { result := viaCepResponse{} res, err := http.Get("https://viacep.com.br/ws/" + cep + "/json/") @@ -35,12 +35,12 @@ func (vc *ViaCepService) Request(cep string) (*structs.Cep, error) { return vc.formater(&result) } -func (vc *ViaCepService) formater(r *structs.ViaCepResponse) (*structs.Cep, error) { +func (vc *ViaCepService) formater(r *viaCepResponse) (*entity.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } - cep := &structs.Cep{ + cep := &entity.Cep{ Cep: r.Cep, City: r.City, Neighborhood: r.Neighborhood, diff --git a/lagoinha.go b/lagoinha.go index e26f0e6..d6c61c9 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -2,6 +2,7 @@ package lagoinha import ( "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/internal/service/viacep" "github.com/igorhalfeld/lagoinha/pkg/errors" ) @@ -15,7 +16,16 @@ func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) return } - chResponse <- &cep + go func(cv string) { + service := viacep.New() + c, err := service.Request(cv) + if err != nil { + chError <- err + return + } + + chResponse <- c + }(cep.Cep) } // GetAddress - get address From 708815d845d78009bdad2aa834c1e5e97312d035 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 16:09:57 -0300 Subject: [PATCH 08/20] fix: package wrong declaration --- internal/service/brasilapi/brasilapi_impl.go | 12 ++++++------ .../{coorreios_impl.go => correios_impl.go} | 10 +++++----- internal/service/widenet/widenet.go | 13 ++++++------- 3 files changed, 17 insertions(+), 18 deletions(-) rename internal/service/correios/{coorreios_impl.go => correios_impl.go} (84%) diff --git a/internal/service/brasilapi/brasilapi_impl.go b/internal/service/brasilapi/brasilapi_impl.go index 2a2b59f..111cd63 100644 --- a/internal/service/brasilapi/brasilapi_impl.go +++ b/internal/service/brasilapi/brasilapi_impl.go @@ -2,20 +2,20 @@ package brasilapi import ( "encoding/json" - "errors" "net/http" "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/pkg/errors" ) type BrasilAPIService struct { } -func New() BrasilAPI { - return &BrasilAPI{} +func New() *BrasilAPIService { + return &BrasilAPIService{} } -func (ba *BrasilAPI) Request(cep string) (*entity.Cep, error) { +func (ba *BrasilAPIService) Request(cep string) (*entity.Cep, error) { result := brasilAPIResponse{} res, err := http.Get("https://brasilapi.com.br/api/cep/v1/" + cep) @@ -30,10 +30,10 @@ func (ba *BrasilAPI) Request(cep string) (*entity.Cep, error) { return nil, err } - return vc.formater(&result) + return ba.formater(&result) } -func (ba *BrasilAPI) formater(r *BrasilAPIResponse) (*entity.Cep, error) { +func (ba *BrasilAPIService) formater(r *brasilAPIResponse) (*entity.Cep, error) { if r == nil { return nil, errors.CepNotFoundError } diff --git a/internal/service/correios/coorreios_impl.go b/internal/service/correios/correios_impl.go similarity index 84% rename from internal/service/correios/coorreios_impl.go rename to internal/service/correios/correios_impl.go index 3ab16fe..583bd29 100644 --- a/internal/service/correios/coorreios_impl.go +++ b/internal/service/correios/correios_impl.go @@ -6,17 +6,17 @@ import ( "errors" "net/http" - "github.com/igorhalfeld/lagoinha/structs" + "github.com/igorhalfeld/lagoinha/internal/entity" ) type CorreiosService struct{} -func New() CorreiosService { +func New() *CorreiosService { return &CorreiosService{} } // Request - fetch data from correios api -func (cs *CorreiosService) Request(cep string) (*structs.Cep, error) { +func (cs *CorreiosService) Request(cep string) (*entity.Cep, error) { const proxyURL = "https://proxier.now.sh/" client := &http.Client{} @@ -56,12 +56,12 @@ func (cs *CorreiosService) Request(cep string) (*structs.Cep, error) { return cs.formater(&result) } -func (cs *CorreiosService) formater(r *structs.CorreiosResponse) (*structs.Cep, error) { +func (cs *CorreiosService) formater(r *correiosResponse) (*entity.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } - cep := &structs.Cep{ + cep := &entity.Cep{ Cep: r.Body.Consult.Return.Cep, City: r.Body.Consult.Return.City, Neighborhood: r.Body.Consult.Return.Neighborhood, diff --git a/internal/service/widenet/widenet.go b/internal/service/widenet/widenet.go index 8d6d37d..e42d83f 100644 --- a/internal/service/widenet/widenet.go +++ b/internal/service/widenet/widenet.go @@ -5,18 +5,17 @@ import ( "errors" "net/http" - "github.com/igorhalfeld/lagoinha/structs" + "github.com/igorhalfeld/lagoinha/internal/entity" ) type WidenetService struct{} -// NewViaCepService creates a new instance -func NewWidenetService() WidenetService { - return &widenetImpl{} +func New() *WidenetService { + return &WidenetService{} } // Request - fetch data from viacep api -func (wn *WidenetService) Request(cep string) (*structs.Cep, error) { +func (wn *WidenetService) Request(cep string) (*entity.Cep, error) { result := widenetResponse{} res, err := http.Get("http://apps.widenet.com.br/busca-cep/api/cep/" + cep + ".json") @@ -34,12 +33,12 @@ func (wn *WidenetService) Request(cep string) (*structs.Cep, error) { return wn.formater(&result) } -func (wn *WidenetService) formater(r *structs.WidenetResponse) (*structs.Cep, error) { +func (wn *WidenetService) formater(r *widenetResponse) (*entity.Cep, error) { if r == nil { return nil, errors.New("Cep not found") } - cep := &structs.Cep{ + cep := &entity.Cep{ Cep: r.Cep, City: r.City, Neighborhood: r.Neighborhood, From 62a105fcee017e97fe87e363110345e22e69b072 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 16:10:10 -0300 Subject: [PATCH 09/20] chore: add another service caller --- lagoinha.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lagoinha.go b/lagoinha.go index d6c61c9..ca0a734 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -2,6 +2,7 @@ package lagoinha import ( "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/internal/service/brasilapi" "github.com/igorhalfeld/lagoinha/internal/service/viacep" "github.com/igorhalfeld/lagoinha/pkg/errors" ) @@ -26,6 +27,17 @@ func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) chResponse <- c }(cep.Cep) + + go func(cv string) { + service := brasilapi.New() + c, err := service.Request(cv) + if err != nil { + chError <- err + return + } + + chResponse <- c + }(cep.Cep) } // GetAddress - get address From 5615b64869765f9e61b9f9ffed8db100fcbea526 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 16:14:41 -0300 Subject: [PATCH 10/20] chore: update docs on README --- README.md | 10 ++++++++-- cmd/main.go | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6fd496b..b4f09d8 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,14 @@ import ( ) func main() { - address, _ := lagoinha.GetAddress("CEP_GOES_HERE") - fmt.Printf("Complete Address %v:", address) + chResp, chErr := lagoinha.GetAddress("04568000") + + select { + case address := <-chResp: + fmt.Printf("Response: %+v\n", address) + case err := <-chErr: + fmt.Printf("Error: %+v\n", err) + } } ``` diff --git a/cmd/main.go b/cmd/main.go index 2ce09f7..771ffe5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -13,6 +13,6 @@ func main() { case address := <-chResp: fmt.Printf("Response: %+v\n", address) case err := <-chErr: - fmt.Printf("Response: %+v\n", err) + fmt.Printf("Error: %+v\n", err) } } From 6bb8da7be9736332ed1ea93bd6a4b6f8245a0fdb Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Wed, 24 Aug 2022 19:15:09 -0300 Subject: [PATCH 11/20] chore: add options params --- cmd/main.go | 2 +- lagoinha.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 771ffe5..5560821 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,7 +7,7 @@ import ( ) func main() { - chResp, chErr := lagoinha.GetAddress("04568000") + chResp, chErr := lagoinha.GetAddress("04568000", nil) select { case address := <-chResp: diff --git a/lagoinha.go b/lagoinha.go index ca0a734..8c3e791 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -40,8 +40,12 @@ func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) }(cep.Cep) } +type GetAddressOptions struct { + PreferenceForAPI string +} + // GetAddress - get address -func GetAddress(cepRaw string) (chan *entity.Cep, chan error) { +func GetAddress(cepRaw string, _ *GetAddressOptions) (chan *entity.Cep, chan error) { chResponse := make(chan *entity.Cep) chError := make(chan error) From 76e9e31a0db441e64cddd9ac7bff9396e058c3d3 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Thu, 25 Aug 2022 14:35:34 -0300 Subject: [PATCH 12/20] chore: fix buff size for response channel --- lagoinha.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lagoinha.go b/lagoinha.go index 8c3e791..e05d85a 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -7,6 +7,9 @@ import ( "github.com/igorhalfeld/lagoinha/pkg/errors" ) +// TotalAmountOfCepProviders returns amount of current enabled cep provivers +const TotalAmountOfCepProviders = 2 + func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) { cep := entity.Cep{ Cep: cepRaw, @@ -46,7 +49,7 @@ type GetAddressOptions struct { // GetAddress - get address func GetAddress(cepRaw string, _ *GetAddressOptions) (chan *entity.Cep, chan error) { - chResponse := make(chan *entity.Cep) + chResponse := make(chan *entity.Cep, TotalAmountOfCepProviders) chError := make(chan error) go getAddress(cepRaw, chResponse, chError) From 006124b3a15d8baab0819a39ecb76e803a65bff0 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Thu, 25 Aug 2022 15:43:33 -0300 Subject: [PATCH 13/20] chore: update default error file name --- pkg/errors/{standard.go => default.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/errors/{standard.go => default.go} (100%) diff --git a/pkg/errors/standard.go b/pkg/errors/default.go similarity index 100% rename from pkg/errors/standard.go rename to pkg/errors/default.go From a28de004accee10aa294e8a82c8681e1608212b6 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Thu, 25 Aug 2022 16:15:36 -0300 Subject: [PATCH 14/20] chore: add TODOs comment --- lagoinha.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lagoinha.go b/lagoinha.go index e05d85a..f7c0e41 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -20,6 +20,7 @@ func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) return } + // TODO: add context.WithCancel for slower requests go func(cv string) { service := viacep.New() c, err := service.Request(cv) From 0c239d928f0cc55e3e2fdaa80c12ef9c61e8eed2 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Sat, 3 Sep 2022 19:33:55 -0300 Subject: [PATCH 15/20] chore: add default interface for services --- internal/service/service.go | 7 +++++++ internal/service/viacep/viacep_impl.go | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 internal/service/service.go diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..546be2d --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,7 @@ +package service + +import "github.com/igorhalfeld/lagoinha/internal/entity" + +type Provider interface { + Request(cep string) (*entity.Cep, error) +} diff --git a/internal/service/viacep/viacep_impl.go b/internal/service/viacep/viacep_impl.go index 9791ec5..6a0b647 100644 --- a/internal/service/viacep/viacep_impl.go +++ b/internal/service/viacep/viacep_impl.go @@ -2,10 +2,10 @@ package viacep import ( "encoding/json" - "errors" "net/http" "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/pkg/errors" ) type ViaCepService struct { @@ -37,7 +37,7 @@ func (vc *ViaCepService) Request(cep string) (*entity.Cep, error) { func (vc *ViaCepService) formater(r *viaCepResponse) (*entity.Cep, error) { if r == nil { - return nil, errors.New("Cep not found") + return nil, errors.CepNotFoundError } cep := &entity.Cep{ @@ -46,7 +46,7 @@ func (vc *ViaCepService) formater(r *viaCepResponse) (*entity.Cep, error) { Neighborhood: r.Neighborhood, State: r.State, Street: r.Street, - Provider: "Viacep", + Provider: "ViaCEP", } return cep, nil From 731a59f380ee18f0404e5fb0e7b036e5ea4dd8ef Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Sat, 3 Sep 2022 19:34:43 -0300 Subject: [PATCH 16/20] chore: add new type of error --- pkg/errors/app.go | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 pkg/errors/app.go diff --git a/pkg/errors/app.go b/pkg/errors/app.go new file mode 100644 index 0000000..134b1ee --- /dev/null +++ b/pkg/errors/app.go @@ -0,0 +1,6 @@ +package errors + +var PreferenceProviderNotFound error = &LagoinhaError{ + Type: ApplicationError, + Message: "preference provider not found", +} From df6ea21cc383cedbe60b6839b0a5ccc5b8b593a3 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Sat, 3 Sep 2022 19:34:57 -0300 Subject: [PATCH 17/20] chore: update API and docs --- README.md | 8 ++++++++ lagoinha.go | 59 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index b4f09d8..476dd5a 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,12 @@ func main() { } ``` +você também pode setar uma api de preferência + +```golang +chResp, chErr := lagoinha.GetAddress("04568000", &lagoinha.GetAddressOptions{ + PreferenceForAPI: "ViaCEP", +}) +``` + logo by [@nelsonsecco](https://twitter.com/nelsonsecco) diff --git a/lagoinha.go b/lagoinha.go index f7c0e41..0726c53 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -2,15 +2,25 @@ package lagoinha import ( "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/internal/service" "github.com/igorhalfeld/lagoinha/internal/service/brasilapi" "github.com/igorhalfeld/lagoinha/internal/service/viacep" "github.com/igorhalfeld/lagoinha/pkg/errors" ) +var providers = map[string]service.Provider{ + "BrasilAPI": brasilapi.New(), + "ViaCEP": viacep.New(), +} + +func GetTotalAmountOfCepProviders() int { + return len(providers) +} + // TotalAmountOfCepProviders returns amount of current enabled cep provivers const TotalAmountOfCepProviders = 2 -func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) { +func getAddress(cepRaw string, opts *GetAddressOptions, chResponse chan *entity.Cep, chError chan error) { cep := entity.Cep{ Cep: cepRaw, } @@ -20,28 +30,37 @@ func getAddress(cepRaw string, chResponse chan *entity.Cep, chError chan error) return } - // TODO: add context.WithCancel for slower requests - go func(cv string) { - service := viacep.New() - c, err := service.Request(cv) - if err != nil { - chError <- err - return - } + // TODO: enhance this way of handling options + if opts != nil { + if opts.PreferenceForAPI != "" { + provider, ok := providers[opts.PreferenceForAPI] + if !ok { + chError <- errors.PreferenceProviderNotFound + } - chResponse <- c - }(cep.Cep) + c, err := provider.Request(cep.Cep) + if err != nil { + chError <- err + return + } - go func(cv string) { - service := brasilapi.New() - c, err := service.Request(cv) - if err != nil { - chError <- err + chResponse <- c return } + } - chResponse <- c - }(cep.Cep) + // TODO: add context.WithCancel for slower requests + for providerName := range providers { + go func(p, cv string) { + c, err := providers[p].Request(cv) + if err != nil { + chError <- err + return + } + + chResponse <- c + }(providerName, cep.Cep) + } } type GetAddressOptions struct { @@ -49,11 +68,11 @@ type GetAddressOptions struct { } // GetAddress - get address -func GetAddress(cepRaw string, _ *GetAddressOptions) (chan *entity.Cep, chan error) { +func GetAddress(cepRaw string, opts *GetAddressOptions) (chan *entity.Cep, chan error) { chResponse := make(chan *entity.Cep, TotalAmountOfCepProviders) chError := make(chan error) - go getAddress(cepRaw, chResponse, chError) + go getAddress(cepRaw, opts, chResponse, chError) return chResponse, chError } From a0c78aa6ddc655bcd4ced85c7483df9ece7bc9e3 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Mon, 5 Sep 2022 20:19:36 -0300 Subject: [PATCH 18/20] chore: update docs and example --- README.md | 2 ++ cmd/main.go | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 476dd5a..3e60690 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ import ( ) func main() { + // get amount of cep providers enabled + fmt.Println("Total amount of cep providers:", lagoinha.GetTotalAmountOfCepProviders()) chResp, chErr := lagoinha.GetAddress("04568000") select { diff --git a/cmd/main.go b/cmd/main.go index 5560821..4c389d9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,7 +7,10 @@ import ( ) func main() { - chResp, chErr := lagoinha.GetAddress("04568000", nil) + fmt.Println("Total amount of cep providers:", lagoinha.GetTotalAmountOfCepProviders()) + chResp, chErr := lagoinha.GetAddress("04568000", &lagoinha.GetAddressOptions{ + PreferenceForAPI: "ViaCEP", + }) select { case address := <-chResp: From 672198822620d203ffaeb9764e86da722c6bef54 Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Fri, 9 Sep 2022 01:15:03 -0300 Subject: [PATCH 19/20] chore: handling for not found provider --- cmd/main.go | 2 +- lagoinha.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index 4c389d9..618bf61 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,7 +9,7 @@ import ( func main() { fmt.Println("Total amount of cep providers:", lagoinha.GetTotalAmountOfCepProviders()) chResp, chErr := lagoinha.GetAddress("04568000", &lagoinha.GetAddressOptions{ - PreferenceForAPI: "ViaCEP", + PreferenceForAPI: "Widenet", }) select { diff --git a/lagoinha.go b/lagoinha.go index 0726c53..a371856 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -36,6 +36,7 @@ func getAddress(cepRaw string, opts *GetAddressOptions, chResponse chan *entity. provider, ok := providers[opts.PreferenceForAPI] if !ok { chError <- errors.PreferenceProviderNotFound + return } c, err := provider.Request(cep.Cep) From c952ff9cd80149d5f47fd9d7e95920656fd43b2c Mon Sep 17 00:00:00 2001 From: Igor Halfeld Date: Fri, 9 Sep 2022 01:26:29 -0300 Subject: [PATCH 20/20] chore: add new provider --- cmd/main.go | 2 +- internal/service/apicep/apicep_impl.go | 51 +++++++++++++++++++++++++ internal/service/apicep/apicep_model.go | 10 +++++ lagoinha.go | 8 ++-- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 internal/service/apicep/apicep_impl.go create mode 100644 internal/service/apicep/apicep_model.go diff --git a/cmd/main.go b/cmd/main.go index 618bf61..e425140 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,7 +9,7 @@ import ( func main() { fmt.Println("Total amount of cep providers:", lagoinha.GetTotalAmountOfCepProviders()) chResp, chErr := lagoinha.GetAddress("04568000", &lagoinha.GetAddressOptions{ - PreferenceForAPI: "Widenet", + PreferenceForAPI: "Apicep", }) select { diff --git a/internal/service/apicep/apicep_impl.go b/internal/service/apicep/apicep_impl.go new file mode 100644 index 0000000..d68ec93 --- /dev/null +++ b/internal/service/apicep/apicep_impl.go @@ -0,0 +1,51 @@ +package apicep + +import ( + "encoding/json" + "net/http" + + "github.com/igorhalfeld/lagoinha/internal/entity" + "github.com/igorhalfeld/lagoinha/pkg/errors" +) + +type ApicepService struct{} + +func New() *ApicepService { + return &ApicepService{} +} + +// Request - fetch data from viacep api +func (wn *ApicepService) Request(cep string) (*entity.Cep, error) { + result := apicepResponse{} + + res, err := http.Get("https://ws.apicep.com/cep/" + cep + ".json") + if err != nil { + return nil, err + } + + defer res.Body.Close() + + err = json.NewDecoder(res.Body).Decode(&result) + if err != nil { + return nil, err + } + + return wn.formater(&result) +} + +func (wn *ApicepService) formater(r *apicepResponse) (*entity.Cep, error) { + if r == nil { + return nil, errors.CepNotFoundError + } + + cep := &entity.Cep{ + Cep: r.Code, + City: r.City, + Neighborhood: r.District, + State: r.State, + Street: r.Address, + Provider: "Apicep", + } + + return cep, nil +} diff --git a/internal/service/apicep/apicep_model.go b/internal/service/apicep/apicep_model.go new file mode 100644 index 0000000..a695148 --- /dev/null +++ b/internal/service/apicep/apicep_model.go @@ -0,0 +1,10 @@ +package apicep + +type apicepResponse struct { + Status int `json:"status"` + Code string `json:"code"` + State string `json:"state"` + City string `json:"city"` + District string `json:"district"` + Address string `json:"address"` +} diff --git a/lagoinha.go b/lagoinha.go index a371856..6276176 100644 --- a/lagoinha.go +++ b/lagoinha.go @@ -3,6 +3,7 @@ package lagoinha import ( "github.com/igorhalfeld/lagoinha/internal/entity" "github.com/igorhalfeld/lagoinha/internal/service" + "github.com/igorhalfeld/lagoinha/internal/service/apicep" "github.com/igorhalfeld/lagoinha/internal/service/brasilapi" "github.com/igorhalfeld/lagoinha/internal/service/viacep" "github.com/igorhalfeld/lagoinha/pkg/errors" @@ -11,15 +12,14 @@ import ( var providers = map[string]service.Provider{ "BrasilAPI": brasilapi.New(), "ViaCEP": viacep.New(), + "Apicep": apicep.New(), } +// GetTotalAmountOfCepProviders returns amount of current enabled cep provivers func GetTotalAmountOfCepProviders() int { return len(providers) } -// TotalAmountOfCepProviders returns amount of current enabled cep provivers -const TotalAmountOfCepProviders = 2 - func getAddress(cepRaw string, opts *GetAddressOptions, chResponse chan *entity.Cep, chError chan error) { cep := entity.Cep{ Cep: cepRaw, @@ -70,7 +70,7 @@ type GetAddressOptions struct { // GetAddress - get address func GetAddress(cepRaw string, opts *GetAddressOptions) (chan *entity.Cep, chan error) { - chResponse := make(chan *entity.Cep, TotalAmountOfCepProviders) + chResponse := make(chan *entity.Cep, GetTotalAmountOfCepProviders()) chError := make(chan error) go getAddress(cepRaw, opts, chResponse, chError)