Go-Back-Skeleton/api/api.go
2017-09-25 20:19:57 +02:00

113 lines
2.8 KiB
Go

package api
import (
"net/http"
"path"
"strings"
"time"
"github.com/dhax/go-base/api/admin"
"github.com/dhax/go-base/api/app"
"github.com/dhax/go-base/auth"
"github.com/dhax/go-base/database"
"github.com/dhax/go-base/email"
"github.com/dhax/go-base/logging"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
"github.com/go-chi/render"
)
// NewAPI configures application resources and routes
func NewAPI() (*chi.Mux, error) {
logger := logging.NewLogger()
db, err := database.DBConn()
if err != nil {
return nil, err
}
emailService, err := email.NewEmailService()
if err != nil {
return nil, err
}
authStore := database.NewAuthStore(db)
authResource, err := auth.NewResource(authStore, emailService)
if err != nil {
return nil, err
}
adminAPI, err := admin.NewAPI(db)
if err != nil {
return nil, err
}
appAPI, err := app.NewAPI(db)
if err != nil {
return nil, err
}
r := chi.NewRouter()
r.Use(middleware.Recoverer)
r.Use(middleware.RequestID)
// r.Use(middleware.RealIP)
r.Use(middleware.DefaultCompress)
r.Use(middleware.Timeout(15 * time.Second))
r.Use(logging.NewStructuredLogger(logger))
r.Use(render.SetContentType(render.ContentTypeJSON))
// use CORS middleware if client is not served by this api, e.g. from other domain or CDN
// r.Use(corsConfig().Handler)
r.Mount("/auth", authResource.Router())
r.Group(func(r chi.Router) {
r.Use(authResource.Token.Verifier())
r.Use(auth.Authenticator)
r.Mount("/admin", adminAPI.Router())
r.Mount("/api", appAPI.Router())
})
r.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("pong"))
})
client := "./public"
r.Get("/*", SPAHandler(client))
return r, nil
}
func corsConfig() *cors.Cors {
// Basic CORS
// for more ideas, see: https://developer.github.com/v3/#cross-origin-resource-sharing
return cors.New(cors.Options{
// AllowedOrigins: []string{"https://foo.com"}, // Use this to allow specific origin hosts
AllowedOrigins: []string{"*"},
// AllowOriginFunc: func(r *http.Request, origin string) bool { return true },
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 86400, // Maximum value not ignored by any of major browsers
})
}
// SPAHandler serves the public Single Page Application
func SPAHandler(publicDir string) http.HandlerFunc {
handler := http.FileServer(http.Dir(publicDir))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
url := r.URL.String()
// serve static files
if strings.Contains(url, ".") || url == "/" {
handler.ServeHTTP(w, r)
return
}
// otherwise always serve index.html
http.ServeFile(w, r, path.Join(publicDir, "/index.html"))
})
}