Decoupled project structure in Go and still use variables initialized in main.go for other package and testing? - go

I am switching to Go from Python/Django. In Django I really liked about its modular Apps project structure design, where each App would have separate bussiness models, routes and views. All the apps would then communicate within the central/project's main routing system and so on.
Django project structure Eg:
- myproject
- myproject
- urls.py
- views.py
...
- planner
- urls.py
- views.py
- models.py
...
I am trying to achieve similar project design in Go project:
- myproject
- cmd
- api
- main.go
- routes.go
- handlers.go
- planner
- routes.go
- handlers.go
- models.go
Excerpt from cmd/api/main.go:
package main
...
db, err := sql.Open("pgx", cfg.db.dsn)
...
srv := &http.Server{
Addr: fmt.Sprintf("localhost:%d", app.config.port),
Handler: app.routes()
}
...
Excerpt from cmd/api/routes.go:
package main
func (app *application) routes() *httprouter.Router {
router := httprouter.New()
planner.Routes(router)
return router
}
Excerpt from cmd/planner/routes.go:
package planner
...
func Routes(router *httprouter.Router) {
router.HandlerFunc(http.MethodPost, "/v1/planner/todos", CreateTodoHandler)
}
Excerpt from cmd/planner/models.go:
package planner
type PlannerModel struct {
DB *sql.DB
}
func (p PlannerModel) InsertTodo(todo *Todo) error {
query := `INSERT INTO todos (title, user_id)
VALUES ($1, $2)
RETURNING id, created_at`
return p.DB.QueryRow(query, todo.Title, todo.UserID).Scan(&todo.ID, &todo.CreatedAt)
}
Now the problem is I need to use the DB connection initialized in cmd/api/main.go file from package main into cmd/planner/handlers.go. Since the variable is from main package I cannot import it into my app's (planner) handler functions.
package planner
func CreateTodoHandler(w http.ResponseWriter, r *http.Request) {
var input struct {
Title string `json:"title"`
UserID int64 `json:"user_id"`
}
err := helpers.ReadJSON(w, r, &input)
...
todo := &Todo{
Title: input.Title,
UserID: input.UserID,
}
...
// How to use/inject DB connection dependency into the PlannerModel?
pm := PlannerModel{
DB: // ????
}
err = pm.InsertTodo(todo)
...
}
I think having a global DB variable solves the problem or a reasonable answer I found was to declare the variable outside in a separate package, and initialize it in main.go. Another approach would be to make the Planner/handlers.go to be of package main and create an application struct in the main package to hold all the models of the project and use it inside the handlers, but I guess this would defeat the decoupled architecture design.
I was wondering what is the preferred way or if there are better ways to go about having similar decoupled project structure like Django, and still use variables initialized in main.go into other packages and do tests?

I had a similar experience when I switched from Python/Django to Go.
The solution to access the db connection in every app is to define structs in each app having a field for db connection, and then create the db connection and all the apps structs in the main.
// planner.go
func (t *Todo) Routes(router *httprouter.Router) {
router.HandlerFunc(http.MethodPost, "/v1/planner/todos", t.CreateTodoHandler)
}
// handlers.go
struct Todo {
DB: *sql.DB
}
func (t *Todo) CreateTodo(w http.ResponseWriter, r *http.Request) {
var input struct {
Title string `json:"title"`
UserID int64 `json:"user_id"`
}
err := helpers.ReadJSON(w, r, &input)
...
todo := &Todo{
Title: input.Title,
UserID: input.UserID,
}
...
pm := PlannerModel{
DB: t.DB
}
err = pm.InsertTodo(todo)
...
}
This would solve your current problem but other problems will arise if you don't have a better design for your application.
I'd recommend reading these two blog posts to better understand designing applications and structuring code in Go.
https://www.gobeyond.dev/standard-package-layout/
https://www.gobeyond.dev/packages-as-layers/

My way is using clean architecture with DI.
Example of repository constructor: https://github.com/zubroide/go-api-boilerplate/blob/master/model/repository/user_repository.go#L16-L19
Example of declaring of repository with db connection: https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L58-L63
Example of using repository in the service declaration: https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L65-L70
This looks similar with other DI's, for example wire.
Pluses are:
no problems with cyclic dependencies,
simplifying of services dependencies support.

Related

How can I separate generated code package and user code but have them accessible from one place in code

I am newer to golang, so I have some courses that I bought from udemy to help break me into the language. One of them I found very helpful for a general understanding as I took on a project in the language.
In the class that I took, all of the sql related functions were in the sqlc folder with the structure less broken out:
sqlc
generatedcode
store
One of those files is a querier that is generated by sqlc that contains an interface with all of the methods that were generated. Here is the general idea of what it currently looks like: https://github.com/techschool/simplebank/tree/master/db/sqlc
package db
import (
"context"
"github.com/google/uuid"
)
type Querier interface {
AddAccountBalance(ctx context.Context, arg AddAccountBalanceParams) (Account, error)
CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error)
...
}
var _ Querier = (*Queries)(nil)
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier? I'm also trying to have it so that the sqlc generated code is in its own folder. The structure I am aiming for is:
sql
sqlc
generatedcode
store - (wraps it all together)
dynamicsqlfiles
This should clear up what a I mean by store: https://github.com/techschool/simplebank/blob/master/db/sqlc/store.go
package db
import (
"context"
"database/sql"
"fmt"
)
// Store defines all functions to execute db queries and transactions
type Store interface {
Querier
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*Queries
}
// NewStore creates a new store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: New(db),
}
}
I'm trying to run everything through that store (both generated and my functions), so I can make a call similar to the CreateUser function in this file (server.store.): https://github.com/techschool/simplebank/blob/master/api/user.go
arg := db.CreateUserParams{
Username: req.Username,
HashedPassword: hashedPassword,
FullName: req.FullName,
Email: req.Email,
}
user, err := server.store.CreateUser(ctx, arg)
if err != nil {
if pqErr, ok := err.(*pq.Error); ok {
switch pqErr.Code.Name() {
case "unique_violation":
ctx.JSON(http.StatusForbidden, errorResponse(err))
return
}
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
I've tried creating something that houses another querier interface that embeds the generated one, then creating my own db.go that uses the generated DBTX interface but has its own Queries struct, and New function. It always gives me an error that the Queries struct I created aren't implementing the functions I made, despite having it implemented in one of the custom methods I made.
I deleted that branch, and have been clicking through the simplebank project linked above to see if I can find another way this could be done, or if I missed something. If it can't be done, that's okay. I'm just using this as a good opportunity to learn a little more about the language, and keep some code separated if possible.
UPDATE:
There were only a few pieces I had to change, but I modified the store.go to look more like:
// sdb is imported, but points to the generated Querier
// Store provides all functions to execute db queries and transactions
type Store interface {
sdb.Querier
DynamicQuerier
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
// NewStore creates a new Store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: sdb.New(db),
dynamicQueries: New(db),
}
}
Then just created a new Querier and struct for the methods I would be creating. Gave them their own New function, and tied it together in the above. Before, I was trying to figure out a way to reuse as much of the generated code as possible, which I think was the issue.
Why I wanted the Interface:
I wanted a structure that separated the files I would be working in more from the files that I would never touch (generated). This is the new structure:
I like how the generated code put everything in the Querier interface, then checked that anything implementing it satisfied all of the function requirements. So I wanted to replicate that for the dynamic portion which I would be creating on my own.
It might be complicating it a bit more than it would 'NEED' to be, but it also provides an additional set of error checking that is nice to have. And in this case, even while maybe not necessary, it ended up being doable.
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier?
If I'm understanding your question correctly I think that you are looking for something like the below (playground):
package main
import (
"context"
"database/sql"
)
// Sample SQL C Code
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
type Queries struct {
db DBTX
}
func (q *Queries) DeleteAccount(ctx context.Context, id int64) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type Querier interface {
DeleteAccount(ctx context.Context, id int64) error
}
//
// Your custom "dynamic" queries
//
type myDynamicQueries struct {
db DBTX
}
func (m *myDynamicQueries) GetDynamicResult(ctx context.Context) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type myDynamicQuerier interface {
GetDynamicResult(ctx context.Context) error
}
// Combine things
type allDatabase struct {
*Queries // Note: You could embed this directly into myDynamicQueries instead of having a seperate struct if that is your preference
*myDynamicQueries
}
type DatabaseFunctions interface {
Querier
myDynamicQuerier
}
func main() {
// Basic example
var db DatabaseFunctions
db = getDatabase()
db.DeleteAccount(context.Background(), 0)
db.GetDynamicResult(context.Background())
}
// getDatabase - Perform whatever is needed to connect to database...
func getDatabase() allDatabase {
sqlc := &Queries{db: nil} // In reality you would use New() to do this!
myDyn := &myDynamicQueries{db: nil} // Again it's often cleaner to use a function
return allDatabase{Queries: sqlc, myDynamicQueries: myDyn}
}
The above is all in one file for simplicity but could easily pull from multiple packages e.g.
type allDatabase struct {
*generatedcode.Queries
*store.myDynamicQueries
}
If this does not answer your question then please show one of your failed attempts (so we can see where you are going wrong).
One general comment - do you really need the interface? A common recommendation is "Accept interfaces, return structs". While this may not always apply I suspect you may be introducing interfaces where they are not really necessary and this may add unnecessary complexity.
I thought that the Store, which was housing both Queriers, was tying it all together. Can you explain a little with the example above (in the question post) why it's not necessary? How does SQLStore get access to all of the Querier interface functions?
The struct SQLStore is what is "tying it all together". As per the Go spec:
Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
So an object of type SQLStore:
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
var foo SQLStore // Assume that we are actually providing values for all fields
Will implement all of the methods of sdb.Queries and, also, those in dynamicQueries (you can also access the sql.DB members via foo.db.XXX). This means that you can call foo.AddAccountBalance() and foo.MyGenericQuery() (assuming that is in dynamicQueries!) etc.
The spec says "In its most basic form an interface specifies a (possibly empty) list of methods". So you can think of an interface as a list of functions that must be implemented by whatever implementation (e.g. struct) you assign to the interface (the interface itself does not implement anything directly).
This example might help you understand.
Hopefully that helps a little (as I'm not sure which aspect you don't understand I'm not really sure what to focus on).

Golang fasthttp router custom logger

I'm playing with fasthttp and it's router, I have no issues with basic things, I have a working server and a router, that is the easy part.
The issue is with the logger, I would like to be able to customize that one, but it does not seem possible with the ctx.Logger() as it only takes a Printf argument and the format is not what I'm looking for.
Does anyone knows where in the documentation I can find a working example of what I want to do?
Example of code I currently have:
package server
import (
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
)
// Router will manage the routes of our API server
func Router() *router.Router {
r := router.New()
r.GET("/", index)
return r
}
func index(ctx *fasthttp.RequestCtx) {
ctx.Logger().Printf("/")
ctx.WriteString("Welcome!")
}
As I'm still trying my hand with the web servers and I still don't understand some things with it and Go also. So An example would be welcome.
For example I would like to be able to do something like that using a logger define in the main package:
package server
import (
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
// Router will manage the routes of our API server
func Router(loger *zap.Logger) *router.Router {
r := router.New()
r.GET("/", index)
return r
}
func index(ctx *fasthttp.RequestCtx) {
ctx.Logger().Printf("/") // Here should print in the zap format of my choice.
ctx.WriteString("Welcome!")
}
If you look at the source code, it's apparent that all you have is the ability to write standard Go-formatted strings:
func (cl *ctxLogger) Printf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
ctxLoggerLock.Lock()
cl.logger.Printf("%.3f %s - %s", time.Since(cl.ctx.ConnTime()).Seconds(), cl.ctx.String(), msg)
ctxLoggerLock.Unlock()
}
The logger simply adds some additional information from the context. So further cutomisation beyond the standard Go formatting does not seem possible. I'm not sure what "zap format of my choice" is, so I can't say if there's a workaround or even if standard Go formatting options will serve for you here.

Create Routing Modules Go/Echo RestAPI

I just started learning Go and want to create my own REST API.
The problem is simple:
I want to have the routes of my api in a different file for example: routes/users.go that then I include in the "main" function and register those routes.
There are a high number of examples of restAPI's in Echo/Go but all of them have the routes in the main() function.
I checked a few examples/github starter kits but it seems that I cannot find a solution that I like.
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
responseJSON := &JSResp{Msg: "Hello World!"}
return c.JSON(http.StatusOK, responseJSON)
})
//I want to get rid of this
e.GET("users", UserController.CreateUser)
e.POST("users", UserController.UpdateUser)
e.DELETE("users", UserController.DeleteUser)
//would like something like
// UserRoutes.initRoutes(e)
e.Logger.Fatal(e.Start(":1323"))
}
//UserController.go
//CreateUser
func CreateUser(c echo.Context) error {
responseJSON := &JSResp{Msg: "Create User!"}
return c.JSON(http.StatusOK, responseJSON)
}
//UserRoutes.go
func initRoutes(e) { //this is probably e* echo or something like that
//UserController is a package in this case that exports the CreateUser function
e.GET("users", UserController.CreateUser)
return e;
}
Is there an easy way to make this? Coming from node.js and still having some syntax errors of course, will solve them, but I am struggling with the architecture of my code at the moment.
I want to have the routes of my api in a different file for example:
routes/users.go that then I include in the "main" function and
register those routes.
This is possible, simply have your files in the routes package declare functions that take an instance of *echo.Echo and have them register the handlers.
// routes/users.go
func InitUserRoutes(e *echo.Echo) {
e.GET("users", UserController.CreateUser)
e.POST("users", UserController.UpdateUser)
e.DELETE("users", UserController.DeleteUser)
}
// routes/posts.go
func InitPostRoutes(e *echo.Echo) {
e.GET("posts", PostController.CreatePost)
e.POST("posts", PostController.UpdatePost)
e.DELETE("posts", PostController.DeletePost)
}
and then in main.go
import (
"github.com/whatever/echo"
"package/path/to/routes"
)
func main() {
e := echo.New()
routes.InitUserRoutes(e)
routes.InitPostRoutes(e)
// ...
}
Note that the InitXxx functions need to start with an upper case letter as opposed to your initRoutes example which has its first letter in lower case. This is because identifiers with lower case first letters are unexported, which makes them inaccessible from outside their own package. Put another way, for you to be able to reference an imported identifier you have to export it by having it start with an upper case letter.
More here: https://golang.org/ref/spec#Exported_identifiers

how to create a context object in google cloud run for firebase

I'm trying to create a context object, so that I can connect to firestore from cloud run, however, all the examples I find on the net basically say I need a context objects, examples I find online usually look like this:
ctx := context.Background()
client, err := firestore.NewClient(ctx, "projectID")
if err != nil {
fail(w, err.Error())
// TODO: Handle error.
}
You can find these examples in places like this one:
https://godoc.org/cloud.google.com/go/firestore#example-NewClient
Nowhere in this example is there an explanation of where to find the context object.
so I just get this error:
undefined: context
I think the documentation is just too confusing.
You should use r.Context() of http.Request object in the request handler instead of initializing a new detached context like context.Background().
The main purpose of contexts is to propagate them, and in Cloud Run you always process requests, so if you pass the request’s context, it’s the right thing to do.
I think in your case, “context” package is not imported. Make sure to use go 1.11+ in your Dockerfile and say:
import “context”
In Go, you need to import packages. For this statement ctx := context.Background() add to the top of your source file import "context" or merge with your existing import set.
Like most languages, the more experience you have the more the language makes sense and you just know what to do. Most languages are the same. In C/C++ you have the include statement, C# the using statement, in Python the import statement, etc.
Google has a large package of examples for using Go and Google Cloud Platform:
Google Cloud Examples in Go
I wrote an article that documents my 30-day journey to learn Go and Google Cloud Platform.
Google Cloud and Go – My Journey to Learn a new Language in 30 days
Given the plethora of 3 lines of code examples that are hard for beginners, and the lack of complete working examples online, like myself, here is a full working example, which is kinda what I needed when I started this task, I hope this helps anybody in the future.
package main
import (
"cloud.google.com/go/firestore" // https://godoc.org/cloud.google.com/go/firestore"
"context" // https://blog.golang.org/context
firebase "firebase.google.com/go"
"fmt"
"log"
"net/http"
"os"
)
func fail(w http.ResponseWriter, msg string) {
fmt.Fprintln(w, "fail:"+msg)
log.Println("fail:" + msg)
}
// State example code
type State struct {
Capital string `firestore:"capital"`
Population float64 `firestore:"pop"` // in millions
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
override := make(map[string]interface{})
ctx := context.Background()
client, err := firestore.NewClient(ctx, "YOURPID")// set GOOGLE_APPLICATION_CREDENTIALS env var
if err != nil {
fail(w, err.Error())
return
}
states := client.Collection("States")
ny := states.Doc("NewYork")
wr, err := ny.Create(ctx, State{
Capital: "Albany",
Population: 19.8,
})
fmt.Println(wr)
})
log.Fatal(http.ListenAndServe("0.0.0.0:8082", nil))
}

Golang service/daos implementation

Coming from a Java background, I have some questions on how things are typically done in Golang. I am specifically talking about services and dao's/repositories.
In java, I would use dependency injection (probably as singleton/application-scoped), and have a Service injected into my rest endpoint / resource.
To give a bit more context. Imagine the following Golang code:
func main() {
http.ListenAndServe("localhost:8080", nil)
}
func init() {
r := httptreemux.New()
api := r.NewGroup("/api/v1")
api.GET("/blogs", GetAllBlogs)
http.Handle("/", r)
}
Copied this directly from my code, main and init are split because google app engine.
So for now I have one handler. In that handler, I expect to interact with a BlogService.
The question is, where, and in what scope should I instantiate a BlogService struct and a dao like datastructure?
Should I do it everytime the handler is triggered, or make it constant/global?
For completeness, here is the handler and blogService:
// GetAllBlogs Retrieves all blogs from GCloud datastore
func GetAllBlogs(w http.ResponseWriter, req *http.Request, params map[string]string) {
c := appengine.NewContext(req)
// need a reference to Blog Service at this point, where to instantiate?
}
type blogService struct{}
// Blog contains the content and meta data for a blog post.
type Blog struct {...}
// newBlogService constructs a new service to operate on Blogs.
func newBlogService() *blogService {
return &blogService{}
}
func (s *blogService) ListBlogs(ctx context.Context) ([]*Blog, error) {
// Do some dao-ey / repository things, where to instantiate BlogDao?
}
You can use context.Context to pass request scoped values into your handlers (available in Go 1.7) , if you build all your required dependencies during the request/response cycle (which you should to avoid race conditions, except for dependencies that manage concurrency on their own like sql.DB). Put all your services into a single container for instance, then query the context for that value :
container := request.Context.Value("container").(*Container)
blogs,err := container.GetBlogService().ListBlogs()
read the following material :
https://golang.org/pkg/context/
https://golang.org/pkg/net/http/#Request.Context

Resources