Giter Club home page Giter Club logo

go-clean-arch's Introduction

go-clean-arch

Changelog

Author's Note

You may notice it diverges from the structures seen in previous versions. I encourage you to explore the branches for each version to select the structure that appeals to you the most. In my recent projects, the code structure has progressed to version 4. However, I do not strictly advocate for one version over another. You may encounter alternative examples on the internet that align more closely with your preferences. Rest assured, the foundational concept will remain consistent or at least bear resemblance. The differences are primarily in the arrangement of directories or the integration of advanced tools directly into the setup.

Description

This is an example of implementation of Clean Architecture in Go (Golang) projects.

Rule of Clean Architecture by Uncle Bob

  • Independent of Frameworks. The architecture does not depend on the existence of some library of feature laden software. This allows you to use such frameworks as tools, rather than having to cram your system into their limited constraints.
  • Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.
  • Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.
  • Independent of Database. You can swap out Oracle or SQL Server, for Mongo, BigTable, CouchDB, or something else. Your business rules are not bound to the database.
  • Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.

More at https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

This project has 4 Domain layer :

  • Models Layer
  • Repository Layer
  • Usecase Layer
  • Delivery Layer

The diagram:

golang clean architecture

The original explanation about this project's structure can read from this medium's post : https://medium.com/@imantumorang/golang-clean-archithecture-efd6d7c43047. It may be different already, but the concept still the same in application level, also you can see the change log from v1 to current version in Master.

How To Run This Project

Make Sure you have run the article.sql in your mysql

Since the project is already use Go Module, I recommend to put the source code in any folder but GOPATH.

Run the Testing

$ make tests

Run the Applications

Here is the steps to run it with docker-compose

#move to directory
$ cd workspace

# Clone into your workspace
$ git clone https://github.com/bxcodec/go-clean-arch.git

#move to project
$ cd go-clean-arch

# copy the example.env to .env
$ cp example.env .env

# Run the application
$ make up

# The hot reload will running

# Execute the call in another terminal
$ curl localhost:9090/articles

Tools Used:

In this project, I use some tools listed below. But you can use any similar library that have the same purposes. But, well, different library will have different implementation type. Just be creative and use anything that you really need.

go-clean-arch's People

Contributors

baorv avatar bogdaan avatar bxcodec avatar dependabot[bot] avatar h4yfans avatar ivanreyeso7 avatar notsu avatar riuvshin avatar sempr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-clean-arch's Issues

Multi-tenancy logic related to repository, usecase or handler layer?

@bxcodec thanks for your amazing work! Go is just a hobby for me and I'm having fun. I'm learning a lot from your project.

I'm trying to understand if multi-tenancy column/table based is something to be "included", if it is "related to" the repository, usecase or handler level.

Example

Adding tenant.go model like this:

package models

type Tenant struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

to other models like this:

package models

type Author struct {
	ID        int64 `json:"id"`
	TenantID  int64 `json:"tenant_id"` // <--- here
	Tenant    *Tenant // <--- here
	Name      string `json:"name"`
	CreatedAt string `json:"created_at"`
	UpdatedAt string `json:"updated_at"`
}

and

package models

import "time"

type Article struct {
	ID        int64 `json:"id"`
	TenantID  int64 `json:"tenant_id"` // <--- here
	Tenant    *Tenant // <--- here
	Title     string    `json:"title" validate:"required"`
	Content   string    `json:"content" validate:"required"`
	Author    Author    `json:"author"`
	UpdatedAt time.Time `json:"updated_at"`
	CreatedAt time.Time `json:"created_at"`
}

Let's talk for example of the Store() method:

Question

Let's say my tenant_id is a field of a User struct in context on every request (authenticated by a third party middleware).

Where do you think I should do something like below? In handler, usecase or repository?

tenantID := GetTenantIDFromUserInContext()
article.TenantID = tenantID

Doubts about fetch queries

Today, before I discover the amazing "clean architecture", I'm using a where clause in my SQL queries (go-pg/pg#1179), like this:

// Used as: "q.Apply(FilterByTenant(ctx))"
func FilterByTenant(ctx context.Context) func(q *orm.Query) (*orm.Query, error) {
	user := ctx.Value(auth.CTXKeyUser).(*models.User)
	return func(q *orm.Query) (*orm.Query, error) {
		q = q.Where("tenant_id = ?", user.TenantID)
		return q, nil
	}
}

I think maybe the concept of FilterByTenant in the usecase layer is an unnecessary repetition and should belong to lower levels like repositories?

But I also think that the main multi-tenancy logic does not change with the change of possible repository types (Postgres, Mysql, Mongo, microservices).

What do you think about it?

Some questions about naming convention.

First of all, Thank you for your awesome idea 👍

  1. In main.go, Is there any reason to name like this? I can't understand the detail feature of this convention with an underscore in front of the package name such as _articleRepo
import (
	_articleHttpDeliver "github.com/bxcodec/go-clean-arch/article/delivery/http"
	_articleRepo "github.com/bxcodec/go-clean-arch/article/repository"
	_articleUcase "github.com/bxcodec/go-clean-arch/article/usecase"
	_authorRepo "github.com/bxcodec/go-clean-arch/author/repository"
)
  1. Could I allow to add the package unrelated with models? (indirectly related?)
    Like below tree, I just define user.go in model and implement authentication feature in auth package. I wanted to separate auth package from user.
    Actually, I'm not sure with this Idea.
.
├── auth
│   ├── delivery
│   │   └── http
│   └── usecase
├── model
└── user
    ├── delivery
    │   └── http
    ├── repository
    └── usecase

Thank you.

Shared functionality between two or more use cases

Thanks for this repo btw.

How would you go about putting in functionality that would be shared between two or more use cases? An example is emailing and the building of those emails from templates.

User or Registration domain with a usecase that will need to send user registration emails
Order domain with a usecase that will need to send order confirmation emails
EmailRepository that does the work of sending the emails
TemplateRepository or AssetRepository that does the work of locating templates

I might do something like the following

EmailRepository
  - sends the emails through an email provider or service
  - Send(email domain.Email) error
TemplateRepository
  - locate templates from the file system, a database, bindata, or other
EmailService or EmailManager
  - contains the logic of turning templates and data into email entities
  - is a domain service it will not use any repositories
  - BuildConfirmationEmail(data {TBD dataType}, templates {TBD templatesType}) domain.Email
OrderUsecase
  - uses EmailRepository, TemplateRepository, EmailService
  - is an application service and uses repositories and domain services

When the User and Order domains want to send emails they'll need to rely on the same three dependencies. This might be OK but I'm not sure and I might have confused a concept or three and that has me tangled up in this knot.

If there were a report component to the application, it may use the same templates repository but would output CSV, Excel, or PDF documents instead. Having a template or assets domain makes sense, I just haven't found the right approach to bringing it together with the logic and other repositories in a shared manner that is used in different usecases that sits well with me.

edit: Giving this some thought and the email problem would probably be best solved using Domain Events. So instead of operating on the aggregate in the User domain performing registration and also sending the email. I would register the user then raise a UserRegistered event that would at minimum have a listener in the Email domain. There the email could be built from templates, or anything, then sent out.

A bonus question regarding this current layout and imports. When there's a handful, say 8-10, modules to import things from do you have any suggestions on organizing or reducing them?

How to handle shared middleware and support functions?

I've been using your go structure for a project I'm working on and I'm hitting a few areas that I'm not quite sure how to solve, at least in a clean architecture way. If we take your directory structure as an example, say we have an http handler for author as well as article. Then say we want to use the same middleware for each handler. How the structure is currently set up is that there's a middleware package within the deliver/http directory for article. Would we have to create the exact same middleware package in author too? Duplicating code is probably not the answer here. Would it be better to create a top level handler/http directory with the middleware in there that can be shared across all entities? How about other utility functions?

[enhancement] Model directory under the domain directory

Thanks for the great project btw.
It is really nice and neat structure, and I'm really enjoying develop project with this architecture.

How would you go about putting some depth on domain directories like below?
Because one domain may have so much of data types and if all that data types exists in just one file (black_ipv4.go in v3 clean-arch), it would be really hard to read the code and would be very fat.

black_ipv4
  - delivery
    - http
      - black_ipv4_handler.go
  - repository
    - black_ipv4_repo.go
  - usecase
    - black_ipv4_usecase.go
  - repository.go
  - usecase.go

domain
  - black_ipv4
    - model
      - attack_vector.go // Attack vector is a core data type indicating the type of attack the black ipv4. was attacking one of our customer's domain.
      - report.go // Report is a data type summarizing the most dangerous black ipv4 in specific period.
      - reputation.go // Reputation of black ipv4 during whole period.
  - custom_error
    - auth.go // Handles error raising during authentication process. To use this API, user must issue api key.
    - server.go // Handles error raising because of server fault which have status code 5xx mostly.

If we struct project like above example there are benefits:

  1. You can import all data types which is used in a domain with just one import sentense: import "github.com/aeharvlee/black-ip-api/black_ipv4/model
  2. You don't have to worry about one big domain file. You can freely add many data types for a domain.
  3. Readability is now good. You can read domain directory like "Oh, black_ipv4 domain have three main data types. attack_vector, report, and reputation. So if I want to add some fields on attack vector, what I do is just add some fields in attack_vector.go

Actually I used version2 features: You can see repository.go and usecase.go in black_ipv4 directory. The reason I use this v2 feature is "Repository and Usecase should use for a domain and should not use for each data types of the domain." It don't make sense use repo for attack_vector under the domain/black_ipv4/attack_vector because what we target is "domain/black_ipv4" not a piece of the domain.

If you don't understand well or need specific examples, please feel free to tell me. I will make an appropriate example on GitHub.

Edit:
If you agree with me, I will edit the source code and proceed with the pull request. Thanks.

The reason I use model directory under the black_ipv4 is for using echo-swagger. echo-swagger confuses because if we don't have model directory, there are two black_ipv4 directories.

Question About Layers

Hi
I am developing my own website using this project structure.
Currently I need to have a logging package and also use of JWT.
For the logging package, is it good idea to put its interface inside domain folder and then implement its methods in adaptors layer?
And for JWT, I think it doesn't need interface as it is less probable to be ejected. So where to put its codes like GenerateToken and ValidateToken methods? if there be a folder called pkg and then putting JWT there, it will go from inner layer to outer layer however.
Could you please help me how to implements tools like jwt and bcrypt. Also where and how to implement a logging feature.
Thanks

Database Connection Error

I'm getting database access denied for root using password yes when running the make up. Below is my compose.yaml

version: "3.7"
services:
web:
image: go-clean-arch
container_name: article_management_api
ports:
- 9090:9090
depends_on:
mysql:
condition: service_healthy
volumes:
- ./config.json:/app/config.json

mysql:
image: mysql:5.7
container_name: go_clean_arch_mysql
command: mysqld --user=root
volumes:
- ./article.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- 3305:3305
environment:
- MYSQL_DATABASE=article
- MYSQL_USER=root
- MYSQL_PASSWORD=
- MYSQL_ROOT_PASSWORD=
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 5s
retries: 10

Why are you passing context to all layers?

Hi!

I am composing it with reference to this repository in my project and I am very grateful!

Why did you pass context to all layers with the following changes?
feat: add context #9

Usage of one usecase into another

First of all, thanks for great articles. It really helps me)

As I understand, it's ok, that usecase layer can be depend on many repositories. We can see it in article_usecse.go But let's imagine, that I have users and sessions. In user we can Create and Delete users. In sessions we can Create and Delete Session. Create and Delete are methods of usecase layer in users and sessions. The problem is in Delete method. If we delete user, we also need to delete sessions. So, it means, that I need to add session usecase Delete to user usecase layer. Is it ok? It can be something like that in main.go

sessionUsecase := NewSessionUsecase(sessionRep)
userUsecase := NewSessionUsecase(userRep, sessionUsecase)

Thank you)

Vulnerability of dependency "golang.org/x/net"

Hello, we are a team researching the dependency management mechanism of Golang. During our analysis, we came across your project and noticed that it contains a vulnerability (CVE-2022-41723). In your project, the golang.org/x/net package is being used at version golang.org/x/net v0.0.0-20180906233101-161cd47e91fd, but the patched version is v0.7.0. To fix the vulnerability, we recommend modifying the go.mod file to update the version to v0.7.0. Thank you for your attention to this matter.

Cyclic Dependence

The code contains a dependency of the database component on the controller component

// We taken ctx from request in controller
ctx := c.Request().Context()

// And controller hand it to usercase
func (a *articleUsecase) fillAuthorDetails(c context.Context, data []domain.Article) ([]domain.Article, error)

// And usercase hand it to repository
func (m *mysqlAuthorRepo) GetByID(ctx context.Context, id int64) (domain.Author, error)

If I would like to use library like a GORM I would need to edit 3 components
For the rest, I would like to note that this is so far the best implementation of pure architecture on golang that I know.

How to manage dependency will be more elegant?

I see these codes in the main.go.

authorRepo := _authorRepo.NewMysqlAuthorRepository(dbConn)
ar := _articleRepo.NewMysqlArticleRepository(dbConn)
timeoutContext := time.Duration(viper.GetInt("context.timeout")) * time.Second
au := _articleUcase.NewArticleUsecase(ar, authorRepo, timeoutContext)
_articleHttpDeliver.NewArticleHttpHandler(e, au)

I think if articleUcase need articleRepo,articleAuthorRepo and more other repository... Dependency management will be terrible, it will produce many codes like "newAriticleUseaCase(ARepo,BRepo,CRepo...)".So if it can be more elegant? I don't think write in the main.go is a good idea.

How to organize another domain?

Hi,I think this is a good repo to study clean-arch, In this demo, It implements a specific domain(article),and in this article directory,It privodes usecase package。If I add another domain(such as author),then I have to package name usecase。So How do I solve this dilemma?

I'm a pythoner turned golang!This transition has been difficult for me.

Dependency Rule Followed?

  • Use case layer imports models
import (
	"context"

	"github.com/bxcodec/go-clean-arch/models"
)

// Usecase represent the article's usecases
type Usecase interface {
	Fetch(ctx context.Context, cursor string, num int64) ([]*models.Article, string, error)
  • Repository layer imports models
import (
	"context"

	"github.com/bxcodec/go-clean-arch/models"
)

// Repository represent the article's repository contract
type Repository interface {
	Fetch(ctx context.Context, cursor string, num int64) (res []*models.Article, nextCursor string, err error)
  • Also the delivery layer is importing models

All the upper layers are referring to models(entities - innermost circle) - "github.com/bxcodec/go-clean-arch/models"

Question?
As the layers does not look like concentric circles, so is the dependency rule followed?

If domain struct does not equal to database's schema, what should be done regarding repository's interface?

I have tried to implement the domain structure where we put our interface of Usecase and Repository in the domain module and are very close to the domain struct.

I very much so liking this approach as it solves our circular dependency, is closer to Domain-driven dev, and abstracts away our model from being too close to the DB schema.

But I have a peculiar case:

I am reimplementing this in an existing service that was up and running, meaning the DB schema is pretty much set (or very hard to migrate). Currently, my DB schema is not quite the same as the domain models, for example (this is not our real case but an example case):

// This is our DB schema
type SchemaUser struct {
	gorm.Model
	UserID               uint
	OtherRelatedID          uint
	Phone                   string
}

// This is our User domain model
type DomainUser struct {
	ID           uint             
	Name         string          
	PhoneNumber  string        
	Email        string            
	DeviceTokens map[string]string 

I found myself confused as to how should I structure the Repository interface. I tried to only put the domain model in the repository interface such as:

type DomainUserRepository interface {
	UpsertUser(ctx context.Context, value *DomainUser) error
        FetchOneByPhone(ctx context.Context, phone string) (*DomainUser, error)
}

But then not every field from SchemaUser is contained inside our DomainUser and vice versa, meaning that:

  • When calling UpsertUser we need to add method params to fill in the blanks -> Not a big problem
  • We need to map the model from DomainUser and SchemaUser, increasing the complexity of the repository
  • When FetchOneByPhone we will have empty fields inside DomainUser -> BIG PROBLEM

What should I do? some of the potential solutions as I understand it:

  • I should refactor DomainUser after all to match with the DB Schema
  • I could just introduce SchemaUser into the domain and allow the repository to have SchemaUser as the method's return value and param
  • I should split the user's implementation into more specific cases, as currently, the definition of Domain user is a bit broad and being handled by several domains.
  • Refactor our DB Schema (not likely)

Any help will be greatly appreciated.

Question about manage 3rd service

Hi, I consider about 3rd service in my repo, where i put this. Like i have a api call to another service in microservice system with REST/gRPC/Kafka/RabbitMQ, etc...

Question: Why use cases are interface?

Hi, Thank you for helping us understanding how to implementation clean architecture in go.

I just wonder why use cases are interfaces instead of just struct with methods.

Problem Running with docker

Hello,
Have tried to run the application using docker, images are built correctly but docker ps only shows one image of mysql.
Please assist on what I'm doing wrong, new to go-lang and docker as well.
Thanks

Repository should be Unexported except by UseCase

Hi! I think Repositories should be unexported by except the usecase, which can be achieved by putting underscore to function name of new repo instance and move the usecase and repo in one domain package for example:

article
├── usecase.go
├── repo.go

The approach above, will force clients to call service rather than calling the new repo instance.

Need sample to replace Delivery layer

Deal all,
with clean architecture, it's independence with Delivery layer, in this case, Mr Bxcodec're using echo.
Any one have example to replace echo lib/framework with gin-gonic?

How do you reference ID's

In domain/article.go we have

type Article struct {
	ID        int64     `json:"id"`
	Title     string    `json:"title" validate:"required"`
	Content   string    `json:"content" validate:"required"`
	Author    Author    `json:"author"`
	UpdatedAt time.Time `json:"updated_at"`
	CreatedAt time.Time `json:"created_at"`
}

Here an Author attribute exists because an Article belongs to an Author

Going from that logic I attempted to add ArticleStats so I made the following changes:

in domain/article.go

type Article struct {
	.
	.
	.
	ArticleStatistics ArticleStats `json:"article_statistics"`
}

and added

in domain/articlestats.go

type ArticleStats struct {
	ID      int64   `json:"id"`
	Article Article `json:"article"`
	.
	.
	.
}

And I get illegal cycle in declaration of Article + illegal cycle in declaration of ArticleStats

How is this solved?

Sample for caching layer

Hey,
thank you for sharing the architecture with us. I believe it's common to have a caching layer (e. g. Redis) between your application and databases (MySQL/MongoDB). I wonder what you'd suggest on how to implement a caching layer here, so that one could query (cached) Authors / Articles?

Questions About Whether Necessary To Use Pointer For Usecase

Thanks a lot for the repo and it is really informative. However I have two small questions about pointer and value for usecase.

  1. In this scenario, article usecase is using pointer in both constructor and method receiver, is it because of the repository dependency(sqldb) which is also a pointer?
  2. What if I have a simpler usecase which doesn't have dependencies of references, eg: repository and it's just used to do simple stateless calculations without extra pointer dependencies. For these kind of scenarios, may I use copies instead of pointers?

I would be very appreciated if you could clear some of my doubts.

Question: Should we use a pointer as a return type of NewUsecase, NewRepository?

In this repo, there are building functios like below(NewUsecase or NewRepository)

type mysqlArticleRepository struct {
	Conn *sql.DB
}

// NewMysqlArticleRepository will create an object that represent the article.Repository interface
func NewMysqlArticleRepository(Conn *sql.DB) domain.ArticleRepository {
	return &mysqlArticleRepository{Conn}
}

As you can see, it returns address using &mysqlArticleRepository which of data type is a pointer.
So I think return type should be pointer *domain.ArticleRepository like below

type mysqlArticleRepository struct {
	Conn *sql.DB
}

// NewMysqlArticleRepository will create an object that represent the article.Repository interface
func NewMysqlArticleRepository(Conn *sql.DB) *domain.ArticleRepository {
	return &mysqlArticleRepository{Conn}
}

I want to hear what you guys think about this.
Thanks for reading this issue. 😄

Directory Setup Questions

Thank you for the article about clean architecture in Go! :)

I had a question about how you set up the packages (directories) in your project:

Question 1 Was there a specific reason that each repository, usecase, and delivery file was packaged under one directory that matched the model name? Why weren't all the repositories under the same directory and the usecases and delivery files the same? (e.g. go-clean-arch/repositories, go-clean-arch/usecases, go-clean-arch/delivery)

Question 2 Also, why are the models not in the same packages as the repository, usecase, and delivery files?

Example: The repository interface/implementation, delivery, and use-case files for "author” were under go-clean-arch/author, but the author model was in the go-clean-arch/models directory.

NOTE: I'm currently trying to clean up my teams Golang project repo and ensure it's scalable for future development, so I'm wondering if the way you set up this repo had a particular reason. :)

Few questions for more complicated application

Hey, thanks for the great work of showing how to apply clean architecture in Go.

I have a few questions with some more complicated situations and I'd like to hear your thought about them. :)

Q1. Who should handle DB transaction?
According to the answer in #1, you mentioned the transaction must be done in Repository layer. However, if the use case is "When a new article is created, a relation between article and author must be created". Does article repository also create the junction record?

Q2. Who should handle cache?
It's very common to see that service has a "find from cache first or fallback to DB query". Does repository handles this logic or use case layer should does this?

Q3. Imagine there are other services want to subscribe "article created" event, which layer should be responsible for publishing this event?

Thanks

Transaction

db object in Repository , In userCase how do i use transaction?

How to handle multiple Repository transactions

I have read your article and code to help me a lot, but I have a question, do not know how to solve, when a business needs multiple Repository cooperation, and they are a transaction, how to deal with such a situation? And this is the majority of cases, can you add similar examples in the code?

More than one repository files?

Hi @bxcodec , thank you for creating this arch.
I have a question, should I create multiple repository files to handle multiple tables?
For Example I have users and user_addresses tables, and then I create user domain to handle both user and user address. If I have separate Create, Update, Delete function between user and user address, should I create two repository files (user_mysql_repo.go and user_address_mysql_repo.go) or I just create one repository file (user_mysql_repo.go).

Thanks

How to implement method on domain

Hello,
May I know how to add hooks to our domain struct? Considering it is swappable, how can I add a hook to any of the domain struct for example using BeforeCreate (gorm hook).
Thank you

Creating different insert operation method vs creating single insert method and reuse in usecase?

Hello,
Sorry for too many questions. I've been studying this architecture lately and came up across this question?

Is it better to create a single Create() method in repository layer and have many usecase methods that creates the entity or having different method for Create() operation in repository layer for so every usecase that requires a Create() method could have it's own dedicated method for creating the entity?

Appreciate your feedback. Thank you and have a nice day ahead.

How do we implement Bulk Update in this design pattern?

Hi,
May I know if there's a way for me to use any ORM update method without fetching the models first, right now from what I can see, the current pattern only allows the repository to update a single model. Is there any pattern that allows updating a single model and bulk update in one repository?
image
Thank you

accept interface, return pointer struct

when creating a constructor in the repository and use case, besides returning an interface, why don't we return the pointer of a struct? any concern about it? maybe in performance or something else?

this authentication plugin is not supported

Hi,

Just tried to test this code just by changing the JSON config to my local MySQL conf after creating the DB but I get this error without any other reference than "this authentication plugin is not supported". Did you already face the same issue?

Thx

Question about directory layer

hi @bxcodec thank for your source

i got a lot of help

I want to know why I classified each directory under the domain.

like

article
├── delivery
│   └── http
│       ├── article_handler.go
│       ├── article_test.go
│       └── middleware
│           ├── middleware.go
│           └── middleware_test.go
├── repository
│   ├── helper.go
│   └── mysql
│       ├── mysql_article.go
│       └── mysqlarticle_test.go
└── usecase
    ├── article_ucase.go
    └── article_ucase_test.go

to

article
├── article_handler.go
├── article_test.go
├── article_ucase.go
├── article_ucase_test.go
├── mysql_article.go
└── mysqlarticle_test.go

why i think this needs, when developing have to open many folders

and this sample usefull msa?

Doubts using gqlgen for graphql endpoint

I'm trying to use the amazing GqlGen (https://github.com/99designs/gqlgen) with your amazing project (thanks again for your work).

I created a PR (#39) for this integration (which you should not accept, it was a mistake: I just wanted to link here my forked branch!).

Is gqlgen in this case just a "third party" delivery layer?

I don't know if I'm doing this well: I'm using just graphql dir in root!

Because - as you can see - code is generated I can just inject usecases in main.go for the graphql.Resolver{}:

e.POST("graphql", echo.WrapHandler(handler.GraphQL(graphql.NewExecutableSchema(graphql.Config{Resolvers: &graphql.Resolver{
    ArticleUsecase: au,
    // <--- other usecases here --->
}}))))

and I use that usecases in resolver.go:

func (r *queryResolver) Articles(ctx context.Context) ([]*models.Article, error) {
	articles, _, err := r.ArticleUsecase.Fetch(ctx, "cursor", 1) // <--- example values because I don't want to change Usecase now
	return articles, err
}

What do you think about?

  1. Am I respecting the principles of "clean architecture"?

  2. Is there a more elegant solution?


A more extensive example of gqlgen in action can be found here: https://github.com/oshalygin/gqlgen-pg-todo-example.
As you can see he's injecting db *pg.DB in main.go file for

Resolvers: &resolvers.Resolver{
	DB: db,
}

How to avoid cyclic dependencies?

Hi!

Lets say, we have a:

package state

import "city"

type State struct {
    ID uint64
    Name string
    Cities []city.City // The list of all cities in this state
}

...

package city

import "state"

type City struct {
    ID uint64
    Name string
    State *state.State // The state to which the city belongs
}

There is a problem of cyclic import, how to handle this kind of situations?
You can say, that we can put state and city into the same package, but...
if we add more realistic cases and examples, this is not a solution anymore:

type Department struct {
    City *city.City // Where is department located
}

and modify type City struct to following:

type City struct {
     // previous fields
    Departments []department.Department
}

Thank you!

Why domain model know about json?

  1. Why domain model know about json (presentation level)?
  2. Why domain model know about input validation?
type Article struct {
	ID        int64     `json:"id"`
	Title     string    `json:"title" validate:"required"`
	Content   string    `json:"content" validate:"required"`
	Author    Author    `json:"author"`
	UpdatedAt time.Time `json:"updated_at"`
	CreatedAt time.Time `json:"created_at"`
}

Maybe better to separate this concerns.

how to add transaction?

i am new web developer, i don't know how to add transaction in the example。

sorry, my english is poor.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.