Basic REST app
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.env
|
||||
config.yaml
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Ask2AgentMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GoImports">
|
||||
<option name="excludedPackages">
|
||||
<array>
|
||||
<option value="github.com/pkg/errors" />
|
||||
<option value="golang.org/x/net/context" />
|
||||
</array>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/quay.iml" filepath="$PROJECT_DIR$/.idea/quay.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import "github.com/gofiber/fiber/v3"
|
||||
|
||||
func HealthCheck(c fiber.Ctx) error {
|
||||
return c.Status(200).JSON(fiber.Map{
|
||||
"status": "ok",
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
type APIError struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"quay/app/handlers"
|
||||
"quay/internal/config"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
func Register(app *fiber.App, cfg *config.Config) {
|
||||
api := app.Group("/api")
|
||||
|
||||
api.Get("/health", handlers.HealthCheck)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
global:
|
||||
token: "${DEPLOY_TOKEN}"
|
||||
github_pat: "${GITHUB_PAT}"
|
||||
storage_path: /var/www/sites
|
||||
|
||||
sites:
|
||||
- repo: my-lib-docs
|
||||
owner: yourname
|
||||
branch: gh-pages
|
||||
domain: docs.my-lib.com
|
||||
|
||||
- repo: portfolio
|
||||
owner: yourname
|
||||
branch: main
|
||||
domain: yourname.com
|
||||
spa: true
|
||||
|
||||
- repo: other-docs
|
||||
owner: yourname
|
||||
branch: gh-pages
|
||||
domain: other-docs.yourdomain.com
|
||||
@@ -0,0 +1,24 @@
|
||||
module quay
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/gofiber/fiber/v3 v3.1.0 // indirect
|
||||
github.com/gofiber/schema v1.7.0 // indirect
|
||||
github.com/gofiber/utils/v2 v2.0.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/klauspost/compress v1.18.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/tinylib/msgp v1.6.3 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.69.0 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/gofiber/fiber/v3 v3.1.0 h1:1p4I820pIa+FGxfwWuQZ5rAyX0WlGZbGT6Hnuxt6hKY=
|
||||
github.com/gofiber/fiber/v3 v3.1.0/go.mod h1:n2nYQovvL9z3Too/FGOfgtERjW3GQcAUqgfoezGBZdU=
|
||||
github.com/gofiber/schema v1.7.0 h1:yNM+FNRZjyYEli9Ey0AXRBrAY9jTnb+kmGs3lJGPvKg=
|
||||
github.com/gofiber/schema v1.7.0/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk=
|
||||
github.com/gofiber/utils/v2 v2.0.2 h1:ShRRssz0F3AhTlAQcuEj54OEDtWF7+HJDwEi/aa6QLI=
|
||||
github.com/gofiber/utils/v2 v2.0.2/go.mod h1:+9Ub4NqQ+IaJoTliq5LfdmOJAA/Hzwf4pXOxOa3RrJ0=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
|
||||
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI=
|
||||
github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,80 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type GlobalConfig struct {
|
||||
Token string `yaml:"token"`
|
||||
GithubPat string `yaml:"github_pat"`
|
||||
StoragePath string `yaml:"storage_path"`
|
||||
}
|
||||
|
||||
type SiteConfig struct {
|
||||
Repo string `yaml:"repo"`
|
||||
Owner string `yaml:"owner"`
|
||||
Branch string `yaml:"branch"`
|
||||
Domain string `yaml:"domain"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Global GlobalConfig `yaml:"global"`
|
||||
Sites []SiteConfig `yaml:"sites"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
Field string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (c Error) Error() string {
|
||||
return "Config error: " + c.Field + " - " + c.Message
|
||||
}
|
||||
|
||||
func validateConfig(config *Config) error {
|
||||
if config.Global.Token == "" {
|
||||
return &Error{Field: "global.token", Message: "Token is required"}
|
||||
}
|
||||
if config.Global.GithubPat == "" {
|
||||
return &Error{Field: "global.github_pat", Message: "GitHub PAT is required"}
|
||||
}
|
||||
if config.Global.StoragePath == "" {
|
||||
return &Error{Field: "global.storage_path", Message: "Storage path is required"}
|
||||
}
|
||||
for i, site := range config.Sites {
|
||||
if site.Repo == "" {
|
||||
return &Error{Field: "sites[" + string(i) + "].repo", Message: "Repo is required"}
|
||||
}
|
||||
if site.Owner == "" {
|
||||
return &Error{Field: "sites[" + string(i) + "].owner", Message: "Owner is required"}
|
||||
}
|
||||
if site.Branch == "" {
|
||||
return &Error{Field: "sites[" + string(i) + "].branch", Message: "Branch is required"}
|
||||
}
|
||||
if site.Domain == "" {
|
||||
return &Error{Field: "sites[" + string(i) + "].domain", Message: "Domain is required"}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Load(path string) (*Config, error) {
|
||||
f, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expanded := os.Expand(string(f), os.Getenv)
|
||||
var config Config
|
||||
err = yaml.Unmarshal([]byte(expanded), &config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = validateConfig(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package envconfig
|
||||
|
||||
import "os"
|
||||
|
||||
type EnvConfig struct {
|
||||
Port string
|
||||
}
|
||||
|
||||
func Load() EnvConfig {
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "4321"
|
||||
}
|
||||
|
||||
return EnvConfig{
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package fiberconfig
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/gofiber/fiber/v3/middleware/logger"
|
||||
)
|
||||
|
||||
func Setup(app *fiber.App) {
|
||||
app.Use(func(c fiber.Ctx) error {
|
||||
c.Set("Content-Type", "application/json")
|
||||
return c.Next()
|
||||
})
|
||||
|
||||
app.Use(logger.New(logger.Config{
|
||||
Format: "[${time}] ${status} - ${method} ${path} (${latency}) - ${ip}\n",
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"quay/app/routes"
|
||||
"quay/internal/config"
|
||||
"quay/internal/envconfig"
|
||||
"quay/internal/fiberconfig"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_ = godotenv.Load()
|
||||
|
||||
envCfg := envconfig.Load()
|
||||
|
||||
cfg, err := config.Load("config.yaml")
|
||||
if err != nil {
|
||||
panic("Failed to load config: " + err.Error())
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
|
||||
fiberconfig.Setup(app)
|
||||
routes.Register(app, cfg)
|
||||
|
||||
log.Fatal(app.Listen(":" + envCfg.Port))
|
||||
}
|
||||
Reference in New Issue
Block a user