add internal/chi/middleware, replace gin with go-chi
This commit is contained in:
parent
ed7ecd8758
commit
aa1e6ad5b8
|
@ -20,7 +20,7 @@ DB_POOL_SIZE=40
|
|||
LOG_DB_QUERIES=true
|
||||
ACCESS_SECRET=access_token_secret
|
||||
FILE_STORAGE_PATH=path_to_the_folder_where_uploaded_files_will_be_stored
|
||||
DISABLE_ACCESS_LOG=false
|
||||
ENABLE_ACCESS_LOG=false
|
||||
```
|
||||
|
||||
1. Clone this repo.
|
||||
|
|
4
go.mod
4
go.mod
|
@ -5,6 +5,7 @@ go 1.16
|
|||
require (
|
||||
github.com/99designs/gqlgen v0.13.0
|
||||
github.com/Kichiyaki/appmode v0.0.0-20210502105643-0a26207c548d
|
||||
github.com/Kichiyaki/chilogrus v0.0.0-20210717074801-6ecc28dbf6b9 // indirect
|
||||
github.com/Kichiyaki/ginlogrus v0.0.0-20210502060406-bb0049cc40c4
|
||||
github.com/Kichiyaki/go-pg-logrus-query-logger/v10 v10.0.0-20210502060056-ad595ba7b858
|
||||
github.com/Kichiyaki/gopgutil/v10 v10.0.0-20210521204542-cc672e361b3d
|
||||
|
@ -13,6 +14,8 @@ require (
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-contrib/cors v1.3.1
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-chi/chi/v5 v5.0.3 // indirect
|
||||
github.com/go-chi/cors v1.2.0 // indirect
|
||||
github.com/go-pg/pg/v10 v10.10.2
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gosimple/slug v1.9.0
|
||||
|
@ -25,5 +28,6 @@ require (
|
|||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/vektah/gqlparser/v2 v2.1.0
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
)
|
||||
|
|
11
go.sum
11
go.sum
|
@ -4,6 +4,10 @@ github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyy
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Kichiyaki/appmode v0.0.0-20210502105643-0a26207c548d h1:ApX13STtfJc2YPH5D2JnBa6+4AM2vt7a81so/MPr/bA=
|
||||
github.com/Kichiyaki/appmode v0.0.0-20210502105643-0a26207c548d/go.mod h1:41p1KTy/fiVocPnJR2h/iXh2NvWWVBdNoZrN8TWVXUI=
|
||||
github.com/Kichiyaki/chilogrus v0.0.0-20210714125912-ed2a840463bf h1:IAr9vs4vth1eX6bbdiiCPO7LPvEiKjGuNmh5D+IGAio=
|
||||
github.com/Kichiyaki/chilogrus v0.0.0-20210714125912-ed2a840463bf/go.mod h1:DkStLjMOKdbuZ/qFps1/fUW+17Glvefijm5NS1KCbIE=
|
||||
github.com/Kichiyaki/chilogrus v0.0.0-20210717074801-6ecc28dbf6b9 h1:ze0F+qhjUaQrZ+3UdZ6Dz3L21T/mZwB6UzzZ8LdG44Y=
|
||||
github.com/Kichiyaki/chilogrus v0.0.0-20210717074801-6ecc28dbf6b9/go.mod h1:DkStLjMOKdbuZ/qFps1/fUW+17Glvefijm5NS1KCbIE=
|
||||
github.com/Kichiyaki/ginlogrus v0.0.0-20210502060406-bb0049cc40c4 h1:1fPLsfbM6DGZcpdV+IeD/52BP7tL33MoVh7FdUGj14g=
|
||||
github.com/Kichiyaki/ginlogrus v0.0.0-20210502060406-bb0049cc40c4/go.mod h1:PTGPHApaVoNA6eEC72vqvzKRhhSUQnHfh9uSho3rsXk=
|
||||
github.com/Kichiyaki/go-pg-logrus-query-logger/v10 v10.0.0-20210502060056-ad595ba7b858 h1:O7EPPY5lWaKbYB/5yJzE8WMesismUYuje7gOemo1UNo=
|
||||
|
@ -45,7 +49,12 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
|||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ=
|
||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi/v5 v5.0.3 h1:khYQBdPivkYG1s1TAzDQG1f6eX4kD2TItYVZexL5rS4=
|
||||
github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
|
||||
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-pg/pg/v10 v10.9.1/go.mod h1:rgmTPgHgl5EN2CNKKoMwC7QT62t8BqsdpEkUQuiZMQs=
|
||||
github.com/go-pg/pg/v10 v10.10.2 h1:8G2DdKrB3/0nRIlpur0HySEWBJnHYUByiC0ko4XzE8w=
|
||||
github.com/go-pg/pg/v10 v10.10.2/go.mod h1:EmoJGYErc+stNN/1Jf+o4csXuprjxcRztBnn6cHe38E=
|
||||
|
@ -251,6 +260,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/pkg/errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/auth"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/model"
|
||||
)
|
||||
|
||||
const (
|
||||
authorizationHeader = "Authorization"
|
||||
)
|
||||
|
||||
var (
|
||||
authenticateKey contextKey = "current_user"
|
||||
)
|
||||
|
||||
func Authenticate(ucase auth.Usecase) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token := extractToken(r.Header.Get("Authorization"))
|
||||
if token != "" {
|
||||
ctx := r.Context()
|
||||
user, err := ucase.ExtractAccessTokenMetadata(ctx, token)
|
||||
if err == nil && user != nil {
|
||||
ctx = context.WithValue(ctx, authenticateKey, user)
|
||||
r = r.WithContext(ctx)
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func UserFromContext(ctx context.Context) (*model.User, error) {
|
||||
user := ctx.Value(authenticateKey)
|
||||
if user == nil {
|
||||
err := errors.New("couldn't retrieve *model.User")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, ok := user.(*model.User)
|
||||
if !ok {
|
||||
err := errors.New("*model.User has wrong type")
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package middleware
|
||||
|
||||
type contextKey string
|
|
@ -0,0 +1,37 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/pkg/errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/dataloader"
|
||||
)
|
||||
|
||||
var (
|
||||
dataLoaderToContext contextKey = "data_loader"
|
||||
)
|
||||
|
||||
func DataLoaderToContext(cfg dataloader.Config) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), dataLoaderToContext, dataloader.New(cfg))
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func DataLoaderFromContext(ctx context.Context) (*dataloader.DataLoader, error) {
|
||||
dataLoader := ctx.Value(dataLoaderToContext)
|
||||
if dataLoader == nil {
|
||||
err := errors.New("couldn't retrieve dataloader.DataLoader")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dl, ok := dataLoader.(*dataloader.DataLoader)
|
||||
if !ok {
|
||||
err := errors.New("dataloader.DataLoader has wrong type")
|
||||
return nil, err
|
||||
}
|
||||
return dl, nil
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func extractToken(bearToken string) string {
|
||||
strArr := strings.Split(bearToken, " ")
|
||||
if len(strArr) == 2 {
|
||||
return strArr[1]
|
||||
}
|
||||
return ""
|
||||
}
|
|
@ -3,16 +3,19 @@ package httpdelivery
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/Kichiyaki/appmode"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/querycomplexity"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/querycomplexity"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/directive"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/resolvers"
|
||||
|
@ -29,21 +32,20 @@ type Config struct {
|
|||
Directive *directive.Directive
|
||||
}
|
||||
|
||||
func Attach(group *gin.RouterGroup, cfg Config) error {
|
||||
func Attach(r chi.Router, cfg Config) error {
|
||||
if cfg.Resolver == nil {
|
||||
return errors.New("cfg.Resolver is required")
|
||||
}
|
||||
gqlHandler := graphqlHandler(prepareConfig(cfg.Resolver, cfg.Directive))
|
||||
group.GET(graphqlEndpoint, gqlHandler)
|
||||
group.POST(graphqlEndpoint, gqlHandler)
|
||||
r.Get(graphqlEndpoint, gqlHandler)
|
||||
r.Post(graphqlEndpoint, gqlHandler)
|
||||
if appmode.Equals(appmode.DevelopmentMode) {
|
||||
group.GET(playgroundEndpoint, playgroundHandler())
|
||||
r.Get(playgroundEndpoint, playgroundHandler())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Defining the GraphQL handler
|
||||
func graphqlHandler(cfg generated.Config) gin.HandlerFunc {
|
||||
func graphqlHandler(cfg generated.Config) http.HandlerFunc {
|
||||
srv := handler.New(generated.NewExecutableSchema(cfg))
|
||||
|
||||
srv.AddTransport(transport.GET{})
|
||||
|
@ -61,19 +63,18 @@ func graphqlHandler(cfg generated.Config) gin.HandlerFunc {
|
|||
srv.Use(extension.Introspection{})
|
||||
}
|
||||
|
||||
return func(c *gin.Context) {
|
||||
c.Header("Cache-Control", "no-store, must-revalidate")
|
||||
srv.ServeHTTP(c.Writer, c.Request)
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Add("Cache-Control", "no-store, must-revalidate")
|
||||
srv.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Defining the Playground handler
|
||||
func playgroundHandler() gin.HandlerFunc {
|
||||
func playgroundHandler() http.HandlerFunc {
|
||||
h := playground.Handler("Playground", graphqlEndpoint)
|
||||
|
||||
return func(c *gin.Context) {
|
||||
c.Header("Cache-Control", fmt.Sprintf(`public, max-age=%d`, playgroundTTL))
|
||||
h.ServeHTTP(c.Writer, c.Request)
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Add("Cache-Control", fmt.Sprintf(`public, max-age=%d`, playgroundTTL))
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
82
main.go
82
main.go
|
@ -3,12 +3,16 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"github.com/Kichiyaki/appmode"
|
||||
"github.com/Kichiyaki/chilogrus"
|
||||
"github.com/Kichiyaki/goutil/envutil"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/chi/middleware"
|
||||
graphqlhttpdelivery "github.com/zdam-egzamin-zawodowy/backend/internal/graphql/delivery/httpdelivery"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/directive"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/resolvers"
|
||||
|
@ -17,7 +21,6 @@ import (
|
|||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/auth/jwt"
|
||||
authusecase "github.com/zdam-egzamin-zawodowy/backend/internal/auth/usecase"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/gin/middleware"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/dataloader"
|
||||
"github.com/zdam-egzamin-zawodowy/backend/internal/postgres"
|
||||
professionrepository "github.com/zdam-egzamin-zawodowy/backend/internal/profession/repository"
|
||||
|
@ -29,13 +32,13 @@ import (
|
|||
userrepository "github.com/zdam-egzamin-zawodowy/backend/internal/user/repository"
|
||||
userusecase "github.com/zdam-egzamin-zawodowy/backend/internal/user/usecase"
|
||||
|
||||
"github.com/Kichiyaki/ginlogrus"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/zdam-egzamin-zawodowy/backend/fstorage"
|
||||
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -45,7 +48,7 @@ func init() {
|
|||
godotenv.Load(".env.local")
|
||||
}
|
||||
|
||||
setupLogger()
|
||||
prepareLogger()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -120,25 +123,28 @@ func main() {
|
|||
logrus.Fatal(errors.Wrap(err, "questionUsecase"))
|
||||
}
|
||||
|
||||
router := setupRouter()
|
||||
graphql := router.Group("")
|
||||
graphql.Use(
|
||||
middleware.GinContextToContext(),
|
||||
middleware.DataLoaderToContext(dataloader.Config{
|
||||
ProfessionRepo: professionRepository,
|
||||
QualificationRepo: qualificationRepository,
|
||||
}),
|
||||
middleware.Authenticate(authUsecase),
|
||||
)
|
||||
graphqlhttpdelivery.Attach(graphql, graphqlhttpdelivery.Config{
|
||||
Resolver: &resolvers.Resolver{
|
||||
AuthUsecase: authUsecase,
|
||||
UserUsecase: userUsecase,
|
||||
ProfessionUsecase: professionUsecase,
|
||||
QualificationUsecase: qualificationUsecase,
|
||||
QuestionUsecase: questionUsecase,
|
||||
},
|
||||
Directive: &directive.Directive{},
|
||||
router := prepareRouter()
|
||||
router.Group(func(r chi.Router) {
|
||||
r.Use(
|
||||
middleware.DataLoaderToContext(dataloader.Config{
|
||||
ProfessionRepo: professionRepository,
|
||||
QualificationRepo: qualificationRepository,
|
||||
}),
|
||||
middleware.Authenticate(authUsecase),
|
||||
)
|
||||
err := graphqlhttpdelivery.Attach(r, graphqlhttpdelivery.Config{
|
||||
Resolver: &resolvers.Resolver{
|
||||
AuthUsecase: authUsecase,
|
||||
UserUsecase: userUsecase,
|
||||
ProfessionUsecase: professionUsecase,
|
||||
QualificationUsecase: qualificationUsecase,
|
||||
QuestionUsecase: questionUsecase,
|
||||
},
|
||||
Directive: &directive.Directive{},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
})
|
||||
srv := &http.Server{
|
||||
Addr: ":8080",
|
||||
|
@ -165,7 +171,7 @@ func main() {
|
|||
logrus.Info("Server exiting")
|
||||
}
|
||||
|
||||
func setupLogger() {
|
||||
func prepareLogger() {
|
||||
if appmode.Equals(appmode.DevelopmentMode) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
@ -183,25 +189,27 @@ func setupLogger() {
|
|||
}
|
||||
}
|
||||
|
||||
func setupRouter() *gin.Engine {
|
||||
router := gin.New()
|
||||
func prepareRouter() *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
|
||||
router.Use(gin.Recovery())
|
||||
if !envutil.GetenvBool("DISABLE_ACCESS_LOG") {
|
||||
router.Use(ginlogrus.Logger(logrus.StandardLogger()))
|
||||
r.Use(chimiddleware.RealIP)
|
||||
if envutil.GetenvBool("ENABLE_ACCESS_LOG") {
|
||||
r.Use(chilogrus.Logger(logrus.StandardLogger()))
|
||||
}
|
||||
r.Use(chimiddleware.Recoverer)
|
||||
|
||||
if appmode.Equals(appmode.DevelopmentMode) {
|
||||
router.Use(cors.New(cors.Config{
|
||||
AllowOriginFunc: func(string) bool {
|
||||
r.Use(cors.Handler(cors.Options{
|
||||
AllowOriginFunc: func(*http.Request, string) bool {
|
||||
return true
|
||||
},
|
||||
AllowCredentials: true,
|
||||
ExposeHeaders: []string{"Authorization"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
|
||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
|
||||
AllowWebSockets: false,
|
||||
ExposedHeaders: []string{"Authorization"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
|
||||
AllowedHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
|
||||
MaxAge: 300,
|
||||
}))
|
||||
}
|
||||
|
||||
return router
|
||||
return r
|
||||
}
|
||||
|
|
Reference in New Issue