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 0000000..343a708 Binary files /dev/null and b/api/favicon.png differ 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())