From 7c1de180f5381a1ffeab44458d64258be28e1020 Mon Sep 17 00:00:00 2001 From: vitor Date: Fri, 18 Oct 2024 12:07:05 -0300 Subject: [PATCH] feat(infra): deploy (#8) * feat(infra): deploy * feat(infra): remove unecessary code * feat(infra): remove comments --- .dockerignore | 27 +++++++++++++++++++++++++++ .github/workflows/fly-deploy.yml | 18 ++++++++++++++++++ Dockerfile | 19 +++++++++++++++++++ api/internal/url-short/http.go | 2 +- api/internal/url-short/service.go | 7 ++++++- api/router/router.go | 19 +++++++++++++++++++ config/api.go | 9 ++++----- config/config_local.hcl | 13 ------------- fly.toml | 27 +++++++++++++++++++++++++++ 9 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/fly-deploy.yml create mode 100644 Dockerfile delete mode 100644 config/config_local.hcl create mode 100644 fly.toml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ecb6476 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# flyctl launch added from .gitignore +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +**/*.exe +**/*.exe~ +**/*.dll +**/*.so +**/*.dylib + +# Test binary, built with `go test -c` +**/*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +**/*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +**/go.work +**/go.work.sum + +# env file +**/.env +fly.toml diff --git a/.github/workflows/fly-deploy.yml b/.github/workflows/fly-deploy.yml new file mode 100644 index 0000000..b0c246e --- /dev/null +++ b/.github/workflows/fly-deploy.yml @@ -0,0 +1,18 @@ +# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ + +name: Fly Deploy +on: + push: + branches: + - main +jobs: + deploy: + name: Deploy app + runs-on: ubuntu-latest + concurrency: deploy-group # optional: ensure only one action runs at a time + steps: + - uses: actions/checkout@v4 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c8a5f3c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +ARG GO_VERSION=1 +FROM golang:${GO_VERSION}-bookworm as builder + +WORKDIR /usr/src/app + +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +COPY . . + +RUN go build -v -o /usr/local/bin/app ./cmd/api + +FROM debian:bookworm + +RUN apt-get update && apt-get install -y ca-certificates && update-ca-certificates + +COPY --from=builder /usr/local/bin/app /usr/local/bin/app + +CMD ["/usr/local/bin/app"] \ No newline at end of file diff --git a/api/internal/url-short/http.go b/api/internal/url-short/http.go index 6d8c1c8..46c0f6e 100644 --- a/api/internal/url-short/http.go +++ b/api/internal/url-short/http.go @@ -19,7 +19,7 @@ func NewHTTP(deps *deps.Deps, db *mongo.Database) *HTTP { } // POST /short-url -func (h *HTTP) ShortUrl(_ http.ResponseWriter, r *http.Request) (interface{}, error) { +func (h *HTTP) ShortUrl(w http.ResponseWriter, r *http.Request) (interface{}, error) { url, err := h.service.ShortUrl(r.Context(), r.Body, *h.service.db.Client()) if err != nil { log.Error(r.Context(), "Failed to create short URL", log.ErrAttr(err)) diff --git a/api/internal/url-short/service.go b/api/internal/url-short/service.go index 2a60962..add7bd9 100644 --- a/api/internal/url-short/service.go +++ b/api/internal/url-short/service.go @@ -4,7 +4,9 @@ import ( "context" "encoding/json" "io" + "os" + "github.com/joho/godotenv" gonanoid "github.com/matoous/go-nanoid" "github.com/vit0rr/short-spot/pkg/deps" "github.com/vit0rr/short-spot/pkg/log" @@ -31,6 +33,9 @@ func NewService(deps *deps.Deps, db *mongo.Database) *Service { // Get short URL func (s *Service) ShortUrl(c context.Context, b io.ReadCloser, dbclient mongo.Client) (*Response, error) { + + godotenv.Load() + var body Body err := json.NewDecoder(b).Decode(&body) if err != nil { @@ -57,7 +62,7 @@ func (s *Service) ShortUrl(c context.Context, b io.ReadCloser, dbclient mongo.Cl }, err } - shortenedUrl := "http://localhost:8080/" + id + shortenedUrl := os.Getenv("BASE_URL") + id coll := dbclient.Database("shortspot").Collection("shorturls") _, err = coll.InsertOne(c, Urls{ diff --git a/api/router/router.go b/api/router/router.go index c0ce2aa..5e10b0a 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -1,6 +1,8 @@ package router import ( + "net/http" + "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" urlshort "github.com/vit0rr/short-spot/api/internal/url-short" @@ -21,6 +23,21 @@ func New(deps *deps.Deps, db mongo.Database) *Router { } } +func corsMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "POST") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + + if r.Method == http.MethodOptions { + w.WriteHeader(http.StatusOK) + return + } + + next.ServeHTTP(w, r) + }) +} + func (router *Router) BuildRoutes() *chi.Mux { r := chi.NewRouter() r.Use(middleware.Recoverer) @@ -29,6 +46,8 @@ func (router *Router) BuildRoutes() *chi.Mux { r.Use(SetResponseTypeToJSON) r.Use(telemetry.TelemetryMiddleware) + r.Use(corsMiddleware) + r.Route("/", func(r chi.Router) { r.Get("/{id}", telemetry.HandleFuncLogger(router.urlshort.Redirect)) r.Route("/short-url", func(r chi.Router) { diff --git a/config/api.go b/config/api.go index b583bfc..0846021 100644 --- a/config/api.go +++ b/config/api.go @@ -17,16 +17,15 @@ type Mongo struct { } func GetDefaultAPIConfig() API { - err := godotenv.Load() - if err != nil { - panic("Error loading .env file") - } + godotenv.Load() return API{ Mongo: Mongo{ - Dsn: fmt.Sprintf("mongodb://%s:%s@localhost:27017", + Dsn: fmt.Sprintf("mongodb+srv://%s:%s@%s/?retryWrites=true&w=majority&appName=%s", os.Getenv("MONGODB_USER"), os.Getenv("MONGODB_PASS"), + os.Getenv("MONGODB_HOST"), + os.Getenv("MONGODB_APPNAME"), ), }, } diff --git a/config/config_local.hcl b/config/config_local.hcl deleted file mode 100644 index 3a3e056..0000000 --- a/config/config_local.hcl +++ /dev/null @@ -1,13 +0,0 @@ -server { - bind_addr = ":8080" - // one of "DEBUG", "INFO", "WARN", "ERROR" - log_level = "INFO" - // in seconds - ctx_timeout = 5 -} - -api { - postgres { - dsn = "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable" - } -} diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..67735e9 --- /dev/null +++ b/fly.toml @@ -0,0 +1,27 @@ +# fly.toml app configuration file generated for short-spot on 2024-10-18T07:25:47-03:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = 'short-spot' +primary_region = 'gig' + +[build] + [build.args] + GO_VERSION = '1.23' + +[env] + BASE_URL="https://short-spot.fly.dev/" + +[http_service] + internal_port = 8080 + force_https = true + auto_stop_machines = 'stop' + auto_start_machines = true + min_machines_running = 0 + processes = ['app'] + +[[vm]] + memory = '1gb' + cpu_kind = 'shared' + cpus = 1