This repository has been archived by the owner on Oct 29, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Redesign the server application structure
There is no singleton anti-pattern now. Server app become extendable and more idiomatic. It moved to flat package structure instead of some different packages for any different needs. Command line app now moved to top level main file.
- Loading branch information
olebedev
committed
Aug 16, 2015
1 parent
fb0a01f
commit 0ad128d
Showing
11 changed files
with
237 additions
and
181 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import ( | ||
"app/server" | ||
"os" | ||
"runtime" | ||
|
||
"github.com/codegangsta/cli" | ||
) | ||
|
||
func main() { | ||
runtime.GOMAXPROCS(runtime.NumCPU()) | ||
Run(os.Args) | ||
} | ||
|
||
// Run creates, configures and runs | ||
// main cli.App | ||
func Run(args []string) { | ||
|
||
app := cli.NewApp() | ||
app.Name = "app" | ||
app.Usage = "React server application" | ||
|
||
configFlag := cli.StringFlag{ | ||
Name: "config, c", | ||
Value: "local", | ||
Usage: "configuration section name", | ||
EnvVar: "CONFIG", | ||
} | ||
|
||
app.Commands = []cli.Command{ | ||
{ | ||
Name: "run", | ||
Usage: "Runs server", | ||
Action: RunServer, | ||
Flags: []cli.Flag{configFlag}, | ||
}, | ||
} | ||
app.Run(args) | ||
} | ||
|
||
// RunServer creates, configures and runs | ||
// main server.App | ||
func RunServer(c *cli.Context) { | ||
app := server.NewApp(server.AppOptions{ | ||
Config: c.String("config"), | ||
}) | ||
app.Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package server | ||
|
||
import ( | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// Api is a defined as struct bundle | ||
// for api. Feel free to organize | ||
// your app as you wish. | ||
type Api struct{} | ||
|
||
// Bind attaches api routes | ||
func (api *Api) Bind(group *gin.RouterGroup) { | ||
group.GET("/v1/conf", api.ConfHandler) | ||
} | ||
|
||
// Serve the app config, for example | ||
func (_ *Api) ConfHandler(c *gin.Context) { | ||
app := c.MustGet("app").(*App) | ||
c.JSON(200, app.Conf.Root) | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package server | ||
|
||
import ( | ||
"app/server/data" | ||
|
||
"github.com/elazarl/go-bindata-assetfs" | ||
"github.com/gin-gonic/gin" | ||
"github.com/nu7hatch/gouuid" | ||
"github.com/olebedev/config" | ||
) | ||
|
||
// There is no singleton anti-pattern, | ||
// all variables defined locally inside | ||
// this struct. | ||
type App struct { | ||
Engine *gin.Engine | ||
Conf *config.Config | ||
React *React | ||
Api *Api | ||
} | ||
|
||
// NewApp returns initialized struct | ||
// of main server application. | ||
func NewApp(opts ...AppOptions) *App { | ||
var options AppOptions | ||
for _, i := range opts { | ||
options = i | ||
i.init() | ||
break | ||
} | ||
|
||
// Parse config yaml string from ./conf.go | ||
conf, err := config.ParseYaml(confString) | ||
Must(err) | ||
// Choise a config section by given string | ||
conf, err = conf.Get(options.Config) | ||
Must(err) | ||
|
||
// Parse environ variables for defined | ||
// in config constants | ||
conf.Env() | ||
|
||
// Set up gin | ||
if !conf.UBool("debug") { | ||
gin.SetMode(gin.ReleaseMode) | ||
} | ||
|
||
// Make an engine | ||
engine := gin.Default() | ||
|
||
// Initialize the application | ||
app := &App{ | ||
Conf: conf, | ||
Engine: engine, | ||
Api: &Api{}, | ||
React: NewReact( | ||
conf.UBool("debug"), | ||
engine, | ||
), | ||
} | ||
|
||
// Define routes and middlewares | ||
app.Engine.StaticFS("/static", &assetfs.AssetFS{ | ||
Asset: data.Asset, | ||
AssetDir: data.AssetDir, | ||
Prefix: "static", | ||
}) | ||
|
||
// Map app struct to access from request handlers | ||
// and middlewares | ||
app.Engine.Use(func(c *gin.Context) { | ||
c.Set("app", app) | ||
}) | ||
|
||
// Avoid favicon react handling | ||
app.Engine.GET("/favicon.ico", func(c *gin.Context) { | ||
c.Redirect(301, "/static/images/favicon.ico") | ||
}) | ||
|
||
// Bind api hadling for URL api.prefix | ||
app.Api.Bind( | ||
app.Engine.Group( | ||
app.Conf.UString("api.prefix"), | ||
), | ||
) | ||
|
||
// Map uuid for every requests | ||
app.Engine.Use(func(c *gin.Context) { | ||
id, _ := uuid.NewV4() | ||
c.Set("uuid", id) | ||
}) | ||
|
||
// Handle all not found routes via react app | ||
app.Engine.NoRoute(app.React.Handle) | ||
|
||
return app | ||
} | ||
|
||
// Run runs the app | ||
func (app *App) Run() { | ||
Must(app.Engine.Run(":" + app.Conf.UString("port"))) | ||
} | ||
|
||
// AppOptions is options struct | ||
type AppOptions struct { | ||
Config string | ||
} | ||
|
||
func (ao *AppOptions) init() { | ||
if ao.Config == "" { | ||
ao.Config = "local" | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,25 @@ | ||
package server | ||
|
||
import ( | ||
. "app/server/utils" | ||
|
||
"github.com/olebedev/config" | ||
) | ||
|
||
var conf *config.Config | ||
|
||
func init() { | ||
c, err := config.ParseYaml(` | ||
// Most easiest way to configure | ||
// an application is define config as | ||
// yaml string and then parse it into | ||
// map. | ||
// How it works see here: | ||
// https://github.com/olebedev/config | ||
var confString = ` | ||
local: | ||
debug: true | ||
port: 5000 | ||
title: lmbd | ||
db: ./db.sqlite | ||
title: Go Starter Kit | ||
api: | ||
prefix: /api | ||
production: | ||
debug: false | ||
port: 5000 | ||
title: lmbd | ||
title: Go Starter Kit | ||
api: | ||
prefix: /api | ||
`) | ||
Must(err) | ||
conf = c | ||
} | ||
` |
Oops, something went wrong.