From a60c7b91cc9604b2a4e4e079cbfd4c85ec1f0129 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 17 Jul 2021 16:06:33 +0700 Subject: [PATCH] feat: implement caching thanks to @ronnygunawan for the insight --- api/app/v1/app.go | 21 ++++++++ api/app/v1/core/jokes.go | 80 +++++++++++++++++++++++++++++ api/app/v1/handler/builder.go | 16 ++++++ api/app/v1/handler/health.go | 4 +- api/app/v1/handler/joke_add.go | 10 +++- api/app/v1/handler/joke_delete.go | 11 +++- api/app/v1/handler/joke_get.go | 59 ++++++++++++--------- api/app/v1/handler/joke_update.go | 14 +++-- api/app/v1/middleware/auth.go | 9 ++-- api/app/v1/models/request.go | 14 +++-- api/app/v1/models/response.go | 2 +- api/app/v1/models/sql.go | 9 ++++ api/app/v1/platform/cache/cache.go | 12 +++++ api/favicon.png | Bin 0 -> 9944 bytes api/go.mod | 2 + api/go.sum | 38 +++++++++++++- api/main.go | 6 ++- 17 files changed, 261 insertions(+), 46 deletions(-) create mode 100644 api/app/v1/core/jokes.go create mode 100644 api/app/v1/handler/builder.go create mode 100644 api/app/v1/models/sql.go create mode 100644 api/app/v1/platform/cache/cache.go create mode 100644 api/favicon.png diff --git a/api/app/v1/app.go b/api/app/v1/app.go index 371c36a..309373c 100644 --- a/api/app/v1/app.go +++ b/api/app/v1/app.go @@ -1,17 +1,38 @@ package v1 import ( + "jokes-bapak2-api/app/v1/core" + "jokes-bapak2-api/app/v1/platform/cache" + "jokes-bapak2-api/app/v1/platform/database" "jokes-bapak2-api/app/v1/routes" + "log" "github.com/gofiber/fiber/v2" + gocache "github.com/patrickmn/go-cache" ) +var memory = cache.InMemory() +var db = database.New() + func New() *fiber.App { app := fiber.New(fiber.Config{ DisableKeepalive: true, CaseSensitive: true, }) + checkCache := core.CheckJokesCache(memory) + + if !checkCache { + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + log.Fatalln(err) + } + memory.Set("jokes", jokes, gocache.NoExpiration) + if err != nil { + log.Fatalln(err) + } + } + routes.Health(app) routes.Joke(app) diff --git a/api/app/v1/core/jokes.go b/api/app/v1/core/jokes.go new file mode 100644 index 0000000..1def352 --- /dev/null +++ b/api/app/v1/core/jokes.go @@ -0,0 +1,80 @@ +package core + +import ( + "context" + "encoding/json" + "jokes-bapak2-api/app/v1/models" + "math/rand" + + "github.com/georgysavva/scany/pgxscan" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/patrickmn/go-cache" +) + +// GetAllJSONJokes +func GetAllJSONJokes(db *pgxpool.Pool) ([]byte, error) { + var jokes []models.Joke + results, err := db.Query(context.Background(), "SELECT \"id\",\"link\" FROM \"jokesbapak2\" ORDER BY \"id\"") + if err != nil { + return nil, err + } + + err = pgxscan.ScanAll(&jokes, results) + if err != nil { + return nil, err + } + + data, err := json.Marshal(jokes) + if err != nil { + return nil, err + } + + return data, nil +} + +// GetRandomJokeFromCache +func GetRandomJokeFromCache(memory *cache.Cache) (string, error) { + jokes, found := memory.Get("jokes") + if !found { + return "", models.ErrNotFound + } + + var data []models.Joke + err := json.Unmarshal(jokes.([]byte), &data) + if err != nil { + return "", nil + } + + random := rand.Intn(len(data)) + joke := data[random].Link + + return joke, nil +} + +// CheckJokesCache checks if there is some value inside jokes cache. +func CheckJokesCache(memory *cache.Cache) bool { + _, found := memory.Get("jokes") + return found +} + +func GetCachedJokeByID(memory *cache.Cache, id int) (string, error) { + jokes, found := memory.Get("jokes") + if !found { + return "", models.ErrNotFound + } + + var data []models.Joke + err := json.Unmarshal(jokes.([]byte), &data) + if err != nil { + return "", nil + } + + // This is a simple solution, might convert it to goroutines and channels sometime soon. + for _, v := range data { + if v.ID == id { + return v.Link, nil + } + } + + return "", nil +} diff --git a/api/app/v1/handler/builder.go b/api/app/v1/handler/builder.go new file mode 100644 index 0000000..59cb394 --- /dev/null +++ b/api/app/v1/handler/builder.go @@ -0,0 +1,16 @@ +package handler + +import ( + "jokes-bapak2-api/app/v1/platform/cache" + "jokes-bapak2-api/app/v1/platform/database" + "time" + + "github.com/Masterminds/squirrel" + "github.com/gojek/heimdall/v7/httpclient" +) + +var psql = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar) +var db = database.New() +var redis = cache.New() +var memory = cache.InMemory() +var client = httpclient.NewClient(httpclient.WithHTTPTimeout(10 * time.Second)) diff --git a/api/app/v1/handler/health.go b/api/app/v1/handler/health.go index dc68edf..8f1942f 100644 --- a/api/app/v1/handler/health.go +++ b/api/app/v1/handler/health.go @@ -13,7 +13,7 @@ func Health(c *fiber.Ctx) error { if err != nil { return c. Status(fiber.StatusServiceUnavailable). - JSON(models.ResponseError{ + JSON(models.Error{ Error: "REDIS: " + err.Error(), }) } @@ -22,7 +22,7 @@ func Health(c *fiber.Ctx) error { if err != nil { return c. Status(fiber.StatusServiceUnavailable). - JSON(models.ResponseError{ + JSON(models.Error{ Error: "POSTGRESQL: " + err.Error(), }) } diff --git a/api/app/v1/handler/joke_add.go b/api/app/v1/handler/joke_add.go index a4ef680..830d161 100644 --- a/api/app/v1/handler/joke_add.go +++ b/api/app/v1/handler/joke_add.go @@ -3,13 +3,15 @@ package handler import ( "context" + "jokes-bapak2-api/app/v1/core" "jokes-bapak2-api/app/v1/models" "github.com/gofiber/fiber/v2" + "github.com/patrickmn/go-cache" ) func AddNewJoke(c *fiber.Ctx) error { - var body models.RequestJokePost + var body models.Joke err := c.BodyParser(&body) if err != nil { return err @@ -25,6 +27,12 @@ func AddNewJoke(c *fiber.Ctx) error { return err } + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + return err + } + memory.Set("jokes", jokes, cache.NoExpiration) + return c.Status(fiber.StatusCreated).JSON(models.ResponseJoke{ Link: body.Link, }) diff --git a/api/app/v1/handler/joke_delete.go b/api/app/v1/handler/joke_delete.go index 370342d..d46c2ce 100644 --- a/api/app/v1/handler/joke_delete.go +++ b/api/app/v1/handler/joke_delete.go @@ -3,10 +3,12 @@ package handler import ( "context" + "jokes-bapak2-api/app/v1/core" "jokes-bapak2-api/app/v1/models" "github.com/Masterminds/squirrel" "github.com/gofiber/fiber/v2" + "github.com/patrickmn/go-cache" ) func DeleteJoke(c *fiber.Ctx) error { @@ -34,11 +36,18 @@ func DeleteJoke(c *fiber.Ctx) error { if err != nil { return err } + + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + return err + } + memory.Set("jokes", jokes, cache.NoExpiration) + return c.Status(fiber.StatusOK).JSON(models.ResponseJoke{ Message: "specified joke id has been deleted", }) } - return c.Status(fiber.StatusNotAcceptable).JSON(models.ResponseError{ + return c.Status(fiber.StatusNotAcceptable).JSON(models.Error{ Error: "specified joke id does not exists", }) } diff --git a/api/app/v1/handler/joke_get.go b/api/app/v1/handler/joke_get.go index fe8e434..61de98a 100644 --- a/api/app/v1/handler/joke_get.go +++ b/api/app/v1/handler/joke_get.go @@ -3,24 +3,17 @@ package handler import ( "context" "io/ioutil" - "log" + "strconv" "time" + "jokes-bapak2-api/app/v1/core" "jokes-bapak2-api/app/v1/models" - "jokes-bapak2-api/app/v1/platform/cache" - "jokes-bapak2-api/app/v1/platform/database" "jokes-bapak2-api/app/v1/utils" - "github.com/Masterminds/squirrel" "github.com/gofiber/fiber/v2" - "github.com/gojek/heimdall/v7/httpclient" + "github.com/patrickmn/go-cache" ) -var psql = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar) -var db = database.New() -var redis = cache.New() -var client = httpclient.NewClient(httpclient.WithHTTPTimeout(10 * time.Second)) - func TodayJoke(c *fiber.Ctx) error { // check from redis if today's joke already exists // send the joke if exists @@ -37,7 +30,6 @@ func TodayJoke(c *fiber.Ctx) error { } if eq { - log.Println("through cached") c.Set("Content-Type", joke.ContentType) return c.Status(fiber.StatusOK).Send([]byte(joke.Image)) } else { @@ -75,11 +67,17 @@ func TodayJoke(c *fiber.Ctx) error { } func SingleJoke(c *fiber.Ctx) error { - // get a joke from db - // fetch the image url - // send the image as proxied file - var link string - err := db.QueryRow(context.Background(), "SELECT \"link\" FROM \"jokesbapak2\" ORDER BY random() LIMIT 1").Scan(&link) + checkCache := core.CheckJokesCache(memory) + + if !checkCache { + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + return err + } + memory.Set("jokes", jokes, cache.NoExpiration) + } + + link, err := core.GetRandomJokeFromCache(memory) if err != nil { return err } @@ -97,20 +95,33 @@ func SingleJoke(c *fiber.Ctx) error { c.Set("Content-Type", response.Header.Get("content-type")) return c.Status(fiber.StatusOK).Send(data) + } func JokeByID(c *fiber.Ctx) error { - // get a joke from db by id - // fetch image url - // send the image as proxied file - var link string - err := db.QueryRow(context.Background(), "SELECT \"link\" FROM \"jokesbapak2\" WHERE \"id\" = $1", c.Params("id")).Scan(&link) - if err != nil { - if err.Error() == "no rows in result set" { - return c.Status(fiber.StatusNotFound).Send([]byte("Requested ID was not found.")) + checkCache := core.CheckJokesCache(memory) + + if !checkCache { + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + return err } + memory.Set("jokes", jokes, cache.NoExpiration) + if err != nil { + return err + } + } + + id, err := strconv.Atoi(c.Params("id")) + if err != nil { return err } + + link, err := core.GetCachedJokeByID(memory, id) + if err != nil { + return err + } + if link == "" { return c.Status(fiber.StatusNotFound).Send([]byte("Requested ID was not found.")) } diff --git a/api/app/v1/handler/joke_update.go b/api/app/v1/handler/joke_update.go index 2471be0..49fafec 100644 --- a/api/app/v1/handler/joke_update.go +++ b/api/app/v1/handler/joke_update.go @@ -3,10 +3,12 @@ package handler import ( "context" + "jokes-bapak2-api/app/v1/core" "jokes-bapak2-api/app/v1/models" "github.com/Masterminds/squirrel" "github.com/gofiber/fiber/v2" + "github.com/patrickmn/go-cache" ) func UpdateJoke(c *fiber.Ctx) error { @@ -19,12 +21,12 @@ func UpdateJoke(c *fiber.Ctx) error { var jokeID string err = db.QueryRow(context.Background(), sql, args...).Scan(&jokeID) - if err != nil { + if err != nil && err != models.ErrNoRows { return err } if jokeID == id { - body := new(models.RequestJokePost) + body := new(models.Joke) err = c.BodyParser(&body) if err != nil { return err @@ -40,13 +42,19 @@ func UpdateJoke(c *fiber.Ctx) error { return err } + jokes, err := core.GetAllJSONJokes(db) + if err != nil { + return err + } + memory.Set("jokes", jokes, cache.NoExpiration) + return c.Status(fiber.StatusOK).JSON(models.ResponseJoke{ Message: "specified joke id has been updated", Link: body.Link, }) } - return c.Status(fiber.StatusNotAcceptable).JSON(models.ResponseError{ + return c.Status(fiber.StatusNotAcceptable).JSON(models.Error{ Error: "specified joke id does not exists", }) } diff --git a/api/app/v1/middleware/auth.go b/api/app/v1/middleware/auth.go index 0b1f9e1..fc548f5 100644 --- a/api/app/v1/middleware/auth.go +++ b/api/app/v1/middleware/auth.go @@ -2,7 +2,6 @@ package middleware import ( "context" - "log" "time" "jokes-bapak2-api/app/v1/models" @@ -18,7 +17,7 @@ var db = database.New() func RequireAuth() fiber.Handler { return func(c *fiber.Ctx) error { - var auth models.RequestAuth + var auth models.Auth err := c.BodyParser(&auth) if err != nil { return err @@ -29,17 +28,15 @@ func RequireAuth() fiber.Handler { if err != nil { return err } - log.Println(args) var token string err = db.QueryRow(context.Background(), sql, args...).Scan(&token) if err != nil { if err.Error() == "no rows in result set" { - return c.Status(fiber.StatusForbidden).JSON(models.ResponseError{ + return c.Status(fiber.StatusForbidden).JSON(models.Error{ Error: "Invalid key", }) } - log.Println("31 - auth.go") return err } @@ -78,7 +75,7 @@ func RequireAuth() fiber.Handler { return c.Next() } - return c.Status(fiber.StatusForbidden).JSON(models.ResponseError{ + return c.Status(fiber.StatusForbidden).JSON(models.Error{ Error: "Invalid key", }) } diff --git a/api/app/v1/models/request.go b/api/app/v1/models/request.go index c01cdaa..6b24ac0 100644 --- a/api/app/v1/models/request.go +++ b/api/app/v1/models/request.go @@ -1,12 +1,16 @@ package models -type RequestJokePost struct { - Link string `json:"link" form:"link"` +type Joke struct { + ID int `json:"id" form:"id" db:"id"` + Link string `json:"link" form:"link" db:"link"` + Creator int `json:"creator" form:"creator" db:"creator"` } -type RequestAuth struct { - Key string `json:"key" form:"key"` - Token string `json:"token" form:"token"` +type Auth struct { + ID int `json:"id" form:"id" db:"id"` + Key string `json:"key" form:"key" db:"key"` + Token string `json:"token" form:"token" db:"token"` + LastUsed string `json:"last_used" form:"last_used" db:"last_used"` } type Today struct { diff --git a/api/app/v1/models/response.go b/api/app/v1/models/response.go index 4f13263..a942ab7 100644 --- a/api/app/v1/models/response.go +++ b/api/app/v1/models/response.go @@ -1,6 +1,6 @@ package models -type ResponseError struct { +type Error struct { Error string `json:"error"` } diff --git a/api/app/v1/models/sql.go b/api/app/v1/models/sql.go new file mode 100644 index 0000000..1eb72c5 --- /dev/null +++ b/api/app/v1/models/sql.go @@ -0,0 +1,9 @@ +package models + +import "errors" + +var ErrNoRows = errors.New("no rows in result set") +var ErrConnDone = errors.New("connection is already closed") +var ErrTxDone = errors.New("transaction has already been committed or rolled back") + +var ErrNotFound = errors.New("record not found") diff --git a/api/app/v1/platform/cache/cache.go b/api/app/v1/platform/cache/cache.go new file mode 100644 index 0000000..24c0588 --- /dev/null +++ b/api/app/v1/platform/cache/cache.go @@ -0,0 +1,12 @@ +package cache + +import ( + "time" + + gocache "github.com/patrickmn/go-cache" +) + +func InMemory() *gocache.Cache { + cache := gocache.New(6*time.Hour, 6*time.Hour) + return cache +} diff --git a/api/favicon.png b/api/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..343a708772f2dea7d54c483972ddd0fd8d4c8605 GIT binary patch literal 9944 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 Wps%uZkAe080000QbNp literal 0 HcmV?d00001 diff --git a/api/go.mod b/api/go.mod index 062c94e..76f3854 100644 --- a/api/go.mod +++ b/api/go.mod @@ -6,10 +6,12 @@ require ( github.com/Masterminds/squirrel v1.5.0 github.com/aldy505/bob v0.0.1 github.com/aldy505/phc-crypto v1.1.0 + github.com/georgysavva/scany v0.2.9 github.com/getsentry/sentry-go v0.11.0 github.com/go-redis/redis/v8 v8.11.0 github.com/gofiber/fiber/v2 v2.14.0 github.com/gojek/heimdall/v7 v7.0.2 github.com/jackc/pgx/v4 v4.11.0 github.com/joho/godotenv v1.3.0 + github.com/patrickmn/go-cache v2.1.0+incompatible ) diff --git a/api/go.sum b/api/go.sum index 9fb707a..07cf40e 100644 --- a/api/go.sum +++ b/api/go.sum @@ -51,6 +51,8 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/cockroach-go/v2 v2.0.3 h1:ZA346ACHIZctef6trOTwBAEvPVm1k0uLm/bb2Atc+S8= +github.com/cockroachdb/cockroach-go/v2 v2.0.3/go.mod h1:hAuDgiVgDVkfirP9JnhXEfcXEPRKBpYdGz+l7mvYSzw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -67,6 +69,7 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -82,6 +85,7 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -92,6 +96,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/georgysavva/scany v0.2.9 h1:Xt6rjYpHnMClTm/g+oZTnoSxUwiln5GqMNU+QeLNHQU= +github.com/georgysavva/scany v0.2.9/go.mod h1:yeOeC1BdIdl6hOwy8uefL2WNSlseFzbhlG/frrh65SA= github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -110,6 +116,7 @@ github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AE github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg0wo= github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= @@ -126,6 +133,7 @@ github.com/gojek/heimdall/v7 v7.0.2 h1:+YutGXZ8oEWbCJIwjRnkKmoTl+Oxt1Urs3hc/FR0s github.com/gojek/heimdall/v7 v7.0.2/go.mod h1:Z43HtMid7ysSjmsedPTXAki6jcdcNVnjn5pmsTyiMic= github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf h1:5xRGbUdOmZKoDXkGx5evVLehuCMpuO1hl701bEQqXOM= github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf/go.mod h1:QzhUKaYKJmcbTnCYCAVQrroCOY7vOOI8cSQ4NbuhYf0= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -206,6 +214,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78= +github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA= github.com/jackc/pgconn v1.8.1 h1:ySBX7Q87vOMqKU2bbmKbUvtYhauDFclYbNDYIE1/h6s= github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= @@ -221,6 +231,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -230,25 +242,36 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik= github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgtype v1.7.0 h1:6f4kVsW01QftE38ufBYxKciO6gyioXSC0ABIRLcZrGs= github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= +github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= github.com/jackc/pgx/v4 v4.11.0 h1:J86tSWd3Y7nKjwT/43xZBvpi04keQWx8gNC2YkdJhZI= github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -288,9 +311,11 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.4.0 h1:TmtCFbH+Aw0AixwyttznSMQDgbR5Yed/Gg6S8Funrhc= +github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -307,6 +332,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= @@ -360,6 +387,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -408,8 +437,9 @@ github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtm github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea h1:jaXWVFZ98/ihXniiDzqNXQgMSgklX4kjfDWZTE3ZtdU= +github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -487,12 +517,14 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -613,6 +645,7 @@ google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -653,6 +686,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/api/main.go b/api/main.go index 8cdc9f7..ab8dd3a 100644 --- a/api/main.go +++ b/api/main.go @@ -13,6 +13,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/etag" + "github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/fiber/v2/middleware/limiter" _ "github.com/joho/godotenv/autoload" ) @@ -46,10 +47,13 @@ func main() { app.Use(cors.New()) app.Use(limiter.New(limiter.Config{ Max: 15, - Duration: 1 * time.Minute, + Expiration: 1 * time.Minute, LimitReached: limitHandler, })) app.Use(etag.New()) + app.Use(favicon.New(favicon.Config{ + File: "./favicon.png", + })) app.Mount("/v1", v1.New())