//go:generate npm --prefix frontend run build package main import ( "embed" "github.com/chi-middleware/logrus-logger" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" "github.com/go-chi/httprate" log "github.com/sirupsen/logrus" httpSwagger "github.com/swaggo/http-swagger" "github.com/tdewolff/minify/v2" "github.com/tdewolff/minify/v2/css" "github.com/tdewolff/minify/v2/html" "github.com/tdewolff/minify/v2/js" "github.com/tdewolff/minify/v2/json" "github.com/tdewolff/minify/v2/svg" "github.com/tdewolff/minify/v2/xml" "io" "io/fs" _ "minify.ccatss.dev/docs" "net/http" "regexp" "strings" "time" ) var ( //go:embed frontend/dist frontendFs embed.FS //go:embed LICENSE.txt licenseBytes []byte ) // @title Minifier API // @version 1.0 // @description An API Implementation of tdewolfe's minify package // @termsOfService http://swagger.io/terms/ // @contact.name ccatss // @contact.url https://ccatss.dev // @contact.email admin@meow.tf // @license.name ISC License // @license.url /LICENSE.txt // @host minify.ccatss.dev // @BasePath /api func main() { r := chi.NewRouter() r.Use(logger.Logger("router", log.StandardLogger())) m := minify.New() m.AddFunc("text/css", css.Minify) m.AddFunc("text/html", html.Minify) m.AddFunc("image/svg+xml", svg.Minify) m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) subFs, err := fs.Sub(frontendFs, "frontend/dist") if err != nil { log.WithError(err).Fatalln("Unable to load frontend") } httpFs := http.FileServer(http.FS(subFs)) r.Handle("/", httpFs) r.Handle("/js/*", httpFs) r.Handle("/css/*", httpFs) r.Get("/LICENSE.txt", func(w http.ResponseWriter, r *http.Request) { w.Write(licenseBytes) }) r.Get("/swagger/*", httpSwagger.Handler( httpSwagger.URL("/swagger/doc.json"), //The url pointing to API definition )) r.Route("/api", func(r chi.Router) { r.Use(httprate.LimitByIP(100, 1*time.Minute)) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"https://*", "http://*"}, AllowedMethods: []string{"GET", "POST", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Content-Type"}, ExposedHeaders: []string{"Link"}, AllowCredentials: false, MaxAge: 300, // Maximum value not ignored by any of major browsers })) r.Post("/", minifyContent("", m)) r.Post("/css", minifyCss(m)) r.Post("/html", minifyHtml(m)) r.Post("/svg", minifySVG(m)) r.Post("/js", minifyJS(m)) r.Post("/json", minifyJSON(m)) r.Post("/xml", minifyXML(m)) }) http.ListenAndServe(":3000", r) } // Minify godoc // @Summary Minify content // @Description Minify content based on input type // @Param input body string false "Input text" // @Accept html,text/css,image/svg+xml,application/javascript,json,xml // @Produce text/plain // @Success 200 {string} string "Minified content" // @Router / [post] func minifyContent(mediaType string, min *minify.M) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if mediaType == "" { mediaType = r.Header.Get("Content-Type") if idx := strings.Index(mediaType, ";"); idx != -1 { mediaType = mediaType[0:idx] } } _, err := io.Copy(w, min.Reader(mediaType, r.Body)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } } // Minify CSS godoc // @Summary Minify CSS // @Description Minify CSS Input // @Param input body string false "Input CSS" // @Accept text/css // @Produce text/css // @Success 200 {string} string "Minified CSS" // @Router /css [post] func minifyCss(min *minify.M) http.HandlerFunc { return minifyContent("text/css", min) } // Minify HTML godoc // @Summary Minify HTML // @Description Minify HTML Input // @Param input body string false "Input HTML" // @Accept html // @Produce html // @Success 200 {string} string "Minified HTML" // @Router /html [post] func minifyHtml(min *minify.M) http.HandlerFunc { return minifyContent("text/html", min) } // Minify SVG godoc // @Summary Minify SVG // @Description Minify SVG Input // @Param input body string false "Input SVG" // @Accept image/svg+xml // @Produce image/svg+xml // @Success 200 {string} string "Minified SVG" // @Router /svg [post] func minifySVG(min *minify.M) http.HandlerFunc { return minifyContent("image/svg+xml", min) } // Minify JS godoc // @Summary Minify JavaScript // @Description Minify JavaScript Input // @Param input body string false "Input JavaScript" // @Accept application/javascript // @Produce application/javascript // @Success 200 {string} string "Minified JavaScript" // @Router /js [post] func minifyJS(min *minify.M) http.HandlerFunc { return minifyContent("application/javascript", min) } // Minify JSON godoc // @Summary Minify JSON // @Description Minify JSON Input // @Param input body string false "Input JSON" // @Accept application/json // @Produce application/json // @Success 200 {string} string "Minified JSON" // @Router /json [post] func minifyJSON(min *minify.M) http.HandlerFunc { return minifyContent("application/json", min) } // Minify XML godoc // @Summary Minify XML // @Description Minify XML Input // @Param input body string false "Input XML" // @Accept xml // @Produce xml // @Success 200 {string} string "Minified XML" // @Router /xml [post] func minifyXML(min *minify.M) http.HandlerFunc { return minifyContent("text/xml", min) }