{"id":25061541,"url":"https://github.com/irahardianto/service-pattern-go","last_synced_at":"2026-01-14T13:04:23.275Z","repository":{"id":37319157,"uuid":"99062517","full_name":"irahardianto/service-pattern-go","owner":"irahardianto","description":"Simple clean Go REST API architecture with dependency injection and mocking example, following SOLID principles.","archived":false,"fork":false,"pushed_at":"2021-08-18T23:14:47.000Z","size":8007,"stargazers_count":870,"open_issues_count":4,"forks_count":121,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-02-06T16:10:18.882Z","etag":null,"topics":["api","circuit-breaker","clean-architecture","dependency-injection","design-patterns","go","golang","mock","rest-api","solid","solid-principles","unit-testing"],"latest_commit_sha":null,"homepage":"https://irahardianto.github.io/service-pattern-go/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/irahardianto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-02T02:20:11.000Z","updated_at":"2025-02-05T16:30:45.000Z","dependencies_parsed_at":"2022-08-03T04:16:10.988Z","dependency_job_id":null,"html_url":"https://github.com/irahardianto/service-pattern-go","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/irahardianto/service-pattern-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irahardianto%2Fservice-pattern-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irahardianto%2Fservice-pattern-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irahardianto%2Fservice-pattern-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irahardianto%2Fservice-pattern-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/irahardianto","download_url":"https://codeload.github.com/irahardianto/service-pattern-go/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/irahardianto%2Fservice-pattern-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28420816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:47:48.104Z","status":"ssl_error","status_checked_at":"2026-01-14T10:46:19.031Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","circuit-breaker","clean-architecture","dependency-injection","design-patterns","go","golang","mock","rest-api","solid","solid-principles","unit-testing"],"created_at":"2025-02-06T16:02:31.174Z","updated_at":"2026-01-14T13:04:23.251Z","avatar_url":"https://github.com/irahardianto.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"service-pattern-go\n-------\n\nHey! Welcome, this is an example of simple REST API implementation with clean architecture written in Go with complete Dependency Injection along with Mocking example, following SOLID principles.\n\nInspired by [Manuel Kiessling go-cleanarchitecture](http://manuel.kiessling.net/2012/09/28/applying-the-clean-architecture-to-go-applications/) and [Joshua Partogi TDD training session](https://github.com/jpartogi/tennis-kata-laravel/)\n\nIt has simple dependencies:\n\n - [Chi (Router)](https://github.com/go-chi/chi)\n - [Testify (Test \u0026 Mock framework)](https://github.com/stretchr/testify)\n - [Mockery (Mock generator)](https://github.com/vektra/mockery)\n - [Hystrix-Go (Circuit Breaker)](https://github.com/afex/hystrix-go)\n\nGet Started:\n\n - [Install](https://irahardianto.github.io/service-pattern-go/#install)\n - [Introduction](https://irahardianto.github.io/service-pattern-go/#introduction)\n - [Folder Structure](https://irahardianto.github.io/service-pattern-go/#folder-structure)\n - [Depency Injection](https://irahardianto.github.io/service-pattern-go/#dependency-injection)\n - [Mocking](https://irahardianto.github.io/service-pattern-go/#mocking)\n - [Testing](https://irahardianto.github.io/service-pattern-go/#testing)\n - [Circuit Breaker](https://irahardianto.github.io/service-pattern-go/#circuit-breaker)\n\n\n----------\n\n[Install](https://irahardianto.github.io/service-pattern-go/#install)\n-------\n\nClone the source\n\n    git clone https://github.com/irahardianto/service-pattern-go\n\nSetup dependencies\n\n    go get -u github.com/go-chi/chi\n    go get -u github.com/jinzhu/gorm\n    go get github.com/stretchr/testify\n    go get github.com/vektra/mockery/.../\n    go get github.com/afex/hystrix-go/hystrix\n    go get -u github.com/mattn/go-sqlite3\n\nSetup sqlite data structure\n\n    sqlite3 /var/tmp/tennis.db \u003c setup.sql\n\nTest first for your liking\n\n    go test ./... -v\n\nRun the app\n\n    go build \u0026\u0026 ./service-pattern-go\n\nAnd visit\n\n    http://localhost:8080/getScore/Rafael/vs/Serena\n\n\n----------\n\n[Introduction](https://irahardianto.github.io/service-pattern-go/#introduction)\n-------\nThis is an example of Go clean architecture implementing Dependency Injection and Mocking for unit testing purposes to achieve safe, reliable and secure source code.\n\nThe idea of the pattern itself is to create decoupled systems that the implementation of lower level domain is not a concern of the implementor, and can be replaced without having concern of breaking implementor function.\n\nThe aim of the architecture is to produce a system that are:\n\n - Independent of frameworks. The system should be able to become an independent system, not bound into any framework implementation that cause the system to be bloated, instead those framework should be used as a tools to support the system implementation rather than limiting the system capabilities.\n - Highly testable. All codes are guilty and tests is the only way we can prove it otherwise, this means that our test coverage has to be able to cover as much layers as we can so we can be sure of our code reliability.\n - Independent of database. Business logic should not be bound to the database, the system should be able to swap MySQL, Maria DB, PosgreSQL, Mongo DB, Dynamo DB without breaking the logic.\n - Independent of 3rd party library. No 3rd party library should be implemented directly to the system logic, we should abstract in away that our system can replace the library anytime we want.\n\nEvery implementation should only be by using interface, there should be no direct access from the implementor to implementation, that way we can inject its dependency and replace it with mock object during unit tests. For example:\n\nPlayerService -\u003e implement IPlayerRepository, instead of direct PlayerRepository\n\n\n    type PlayerService struct {\n      interfaces.IPlayerRepository\n    }\n\n    func (service *PlayerService) GetScores(player1Name string, player2Name string) (string, error) {\n\n      baseScore := [4]string{\"Love\", \"Fifteen\", \"Thirty\", \"Forty\"}\n      var result string\n\n      player1, err := service.GetPlayerByName(player1Name)\n      if err != nil {\n        //Handle error\n      }\n\n      player2, err := service.GetPlayerByName(player2Name)\n      if err != nil {\n        //Handle error\n      }\n\n      if player1.Score \u003c 4 \u0026\u0026 player2.Score \u003c 4 \u0026\u0026 !(player1.Score+player2.Score == 6) {\n\n        s := baseScore[player1.Score]\n\n        if player1.Score == player2.Score {\n          result = s + \"-All\"\n        } else {\n           result = s + \"-\" + baseScore[player2.Score]\n        }\n      }\n\n      if player1.Score == player2.Score {\n        result = \"Deuce\"\n      }\n\n      return result, nil\n    }\n    \nIf you look into the implementation of these lines\n\n    player1, err := service.GetPlayerByName(player1Name)\n    player2, err := service.GetPlayerByName(player2Name)\n\nBoth are actually abstract implementation of the interface, not the real implementation itself.\nSo later on the Dependency Injection section, we will learn those interface will be injected with the implementation during the compile time. This way, we can switch the implementation of IPlayerService \u0026 IPlayerRepository during the injection with whatever implementation without changing the implementation logic.\n\nThroughout this repo you will find implementation of design patterns such as **Strategy Pattern** when we inject our dependencies with the real implementations. We create **Singleton** and use it to wired up our router and services. We use **Composite** for all our abstract interface implementations so that the implementor can abstractly implement the methods it has, just as the example above where **PlayerService** implements **interfaces.IPlayerRepository** and allows it to directly invoke **GetPlayerByName** which is **IPlayerRepository's** method.  We also use **Decorator Pattern** to hook up our circuit breaker without needing to change / modify the original implementation.\n\n----------\n\n[Folder Structure](https://irahardianto.github.io/service-pattern-go/#folder-structure)\n-------\n    /\n    |- controllers\n    |- infrastructures\n    |- interfaces\n    |- models\n    |- repositories\n    |- services\n    |- viewmodels\n    main.go\n    router.go\n    servicecontainer.go\n\nThe folder structure is created to accomodate seperation of concern principle, where every struct should have single responsibility to achieve decoupled system.\n\nEvery folder is a namespace of their own, and every file / struct under the same folder should only use the same namepace as their root folder.\n\n### controllers\n\ncontrollers folder hosts all the structs under controllers namespace, controllers are the handler of all requests coming in, to the router, its doing just that, business logic and data access layer should be done separately.\n\ncontroller struct implement services through their interface, no direct services implementation should be done in controller, this is done to maintain decoupled systems. The implementation will be injected during the compiled time.\n\n\n### infrasctructures\n\ninfrasctructures folder host all structs under infrasctructures namespace, infrasctructures consists of setup for the system to connect to external data source, it is used to host things like database connection configurations, MySQL, MariaDB, MongoDB, DynamoDB.\n\n### interfaces\n\ninterfaces folder hosts all the structs under interfaces namespace, interfaces as the name suggest are the bridge between different domain so they can interact with each other, in our case, this should be the only way for them to interact.\n\ninterface in Go is a bit different then you might already find in other language like Java or C#, while the later implements interface explicitly, Go implements interface implicitly. You just need to implement all method the interface has, and you're good to \"Go\".\n\nIn our system, our PlayerController implements IPlayerService to be able to interact with the implementation that will be injected. In our case, IPlayerService will be injected with PlayerService.\n\nThe same thing applies on PlayerService which implements IPlayerRepository to be able interact with the injected implementation. In our case, IPlayerRepository will be injected with PlayerRepository during the compile time.\n\nPlayerRepository on the other hand, will be injected with infrasctructure configuration that has been setup earlier, this ensure that you can change the implementation of PlayerRepository, without changing the implementor which in this case PlayerService let alone break it. The same thing goes to PlayerService and PlayerController relationship, we can refactor PlayerService, we can change it however we want, without touching the implementor which is PlayerController.\n\n### models\n\nmodels folder hosts all structs under models namespace, model is a struct reflecting our data object from / to database. models should only define data structs, no other functionalities should be included here.\n\n### repositories\n\nrepositories folder hosts all structs under repositories namespace, repositories is where the implementation of data access layer. All queries and data operation from / to database should happen here, and the implementor should be agnostic of what is the database engine is used, how the queries is done, all they care is they can pull the data according to the interface they are implementing.\n\n### services\n\nservices folder hosts all structs under services namespace, services is where the business logic lies on, it handles controller request and fetch data from data layer it needs and run their logic to satisfy what controller expect the service to return.\n\ncontroller might implement many services interface to satisfy the request needs, and controller should be agnostic of how services implements their logic, all they care is that they should be able to pull the result they need according to the interface they implements.\n\n### viewmodels\n\nviewmodels folder hosts all the structs under viewmodels namespace, viewmodels are model to be use as a response return of REST API call\n\n### main.go\n\nmain.go is the entry point of our system, here lies the router bindings it triggers ChiRouter singleton and call InitRouter to bind the router.\n\n### router.go\n\nrouter.go is where we binds controllers to appropriate route to handle desired http request. By default we are using Chi router as it is a light weight router and not bloated with unnecessary unwanted features.\n\n### servicecontainer.go\n\nservicecontainer.go is where the magic begins, this is the place where we injected all implementations of interfaces. Lets cover throughly in the dependency injection section.\n\n----------\n\n[Dependecy Injection](https://irahardianto.github.io/service-pattern-go/#dependency-injection)\n-------\n\nDependecy injection is the heart of TDD, without it we wont be able to do proper TDD because there will be no mocking and we cannot decoupled our code properly. This is one of the misconception when people thinks that they are doing unit testing instead actually they are doing integration test which connects the logic to database. Unit test should be done independently and database should not come in to play when we are doing unit test. One thing to not though, in Go dependency has to be injected during compile time instead of runtime which cause it a bit different than Java / C# implementation, but anyway, its just plain old dependency injection.\n\nIn essence unit test is created to test our logic not our data integrity, and by taking database during unit testing it will add huge complexity to the tests itself, and this creates barrier for programmers new to unit testing as they are struggling to create proper testing for their functions.\n\nNow why dependency injection is a crucial part in doing proper TDD? the answer lies in the usage of interface. Back when I have never encountered mocking, I always wondering, what is the use of interface, why we should create abstraction for our functions instead of just write it all already, why the hell should we create a duplicate, abstraction that we will be implementing shortly anyway, some says that, because in doing so, your code will be much cleaner and we have proper pattern, I called that bullshit because in essence we dont have to do it if it only for that reason, and I'm still wondering until I learned about mocking.\n\nSome other people says that interface is used so your program is decoupled, and when needed you can replace the implementations without needing to adjust the implementor. That make sense right? much better than the bullshit. Yea that make sense, we can replace whatever implement whatever interface with whatever. Yea, but how many times would you replace you database connection calls? chances are rare if not never especially if you working on software house that deliver projects after projects after projects, you will never see you component got replaced.\n\nThe when I learned about mocking, all that I have been asking coming to conclusions as if I was like having epiphany, we will discuss more about mocking in the mocking section, but for now lets discuss it in regards of dependency injection usage. So as you see in our project structure, instead of having all component directly talks to each other, we are using interface, take PlayerController for example\n\n    type PlayerController struct {\n      interfaces.IPlayerService\n    }\n    \n    func (controller *PlayerController) GetPlayerScore(res http.ResponseWriter, req *http.Request) {\n    \n      player1Name := chi.URLParam(req, \"player1\")\n      player2Name := chi.URLParam(req, \"player2\")\n    \n      scores, err := controller.GetScores(player1Name, player2Name)\n      if err != nil {\n        //Handle error\n      }\n    \n\t  json.NewEncoder(res).Encode(viewmodels.ScoresVM{scores})\n    }\n\nYou see that PlayerController uses IPlayerService interface, and since IPlayerService has GetScores method, PlayerController can invoke it and get the result right away. Wait a minute, isn't that the interface is just merely abstraction? so how do it get executed, where is the implementation?\n\n    type IPlayerService interface {\n      GetScores(player1Name string, player2Name string) (string, error)\n    }\n\nYou see, instead of calling directly to PlayerService, PlayerController uses the interface of PlayerService which is IPlayerService, there could be many implementation of IPlayerService not just limited to PlayerService it could be BrotherService etc, but how do we determined that PlayerService will be used instead?\n\n    func (k *kernel) InjectPlayerController() controllers.PlayerController {\n\n      sqlConn, _ := sql.Open(\"sqlite3\", \"/var/tmp/tennis.db\")\n      sqliteHandler := \u0026infrastructures.SQLiteHandler{}\n      sqliteHandler.Conn = sqlConn\n\n\t  playerRepository := \u0026repositories.PlayerRepository{sqliteHandler}\n\t  playerService := \u0026services.PlayerService{\u0026repositories.PlayerRepositoryWithCircuitBreaker{playerRepository}}\n\t  playerController := controllers.PlayerController{playerService}\n\n      return playerController\n    }\n\nThis is where dependency injection come in to play, as you see here in servicecontainer.go we are creating **playerController** and inject it with **playerService** as simple as that, this is what dependency injection all about no more. So **playerController's IPlayerService** will be injected by **playerService** along with all implementation that it implements, so for example **GetPlayerByName** now returns whatever **GetPlayerByName** implemented by **playerService** as you can see it in **PlayerService.go**\n\nNow, how does this relates to TDD \u0026 mocking?\n\n\tplayerService := new(mocks.IPlayerService)\n\nYou see, in PlayerController_test.go we are using mock object to inject the implementation of our service, lets discuss more detail about mocking and testing in each section.\n\n----------\n\n[Mocking](https://irahardianto.github.io/service-pattern-go/#mocking)\n-------\n\nMocking is a concept many times people struggle to understand, let alone implement it, at least I was the one among the one who struggles to understand this concept. But understanding this concept is essential to do TDD. The key point is, we mock dependencies that we need to run our tests, this is why dependency injection is essential to proceed. We are using testfy as our mock library\n\nBasically what mock object do is replacing injection instead of real implementation with mock as point out at the end of dependency injection session\n\n    playerService := new(mocks.IPlayerService)\n\nWe then create mock GetScores functionalities along with its request and response.\n\n    playerService.On(\"GetScores\", \"Rafael\", \"Serena\").Return(\"Forty-Fifteen\", nil)\n\nAs you see, then the mock object is injected to **playerService** of PlayerController, this is why dependency injection is essential to this proses as it is the only way we can inject interface with mock object instead of real implementation.\n\n\tplayerController := PlayerController{playerService}\n\nWe generate mock our by using vektra mockery for IPlayerService, go to the interfaces folder and then just type.\n\n    mockery -name=IPlayerService\n\nThe output will be inside ```mocks/IPlayerService.go``` and we can use it right away for our testing.\n\n----------\n\n[Testing](https://irahardianto.github.io/service-pattern-go/#testing)\n-------\n\nWe have cover pretty much everything there is I hope that you already get the idea of proper unit testing and why we should implement interfaces, dependency injection and mocking. The last piece is the unit test itself.\n\n    func TestPlayerScore(t *testing.T) {\n\n      // create an instance of our test object\n      playerService := new(mocks.IPlayerService)\n\n      // setup expectations\n      playerService.On(\"GetScores\", \"Rafael\", \"Serena\").Return(\"Forty-Fifteen\", nil)\n\n\t  playerController := PlayerController{playerService}\n\n      // call the code we are testing\n      req := httptest.NewRequest(\"GET\", \"http://localhost:8080/getScore/Rafael/vs/Serena\", nil)\n      w := httptest.NewRecorder()\n\n      r := chi.NewRouter()\n      r.HandleFunc(\"/getScore/{player1}/vs/{player2}\", playerController.GetPlayerScore)\n\n      r.ServeHTTP(w, req)\n\n      expectedResult := viewmodels.ScoresVM{}\n      expectedResult.Score = \"Forty-Fifteen\"\n\n      actualResult := viewmodels.ScoresVM{}\n\n      json.NewDecoder(w.Body).Decode(\u0026actualResult)\n\n      // assert that the expectations were met\n      assert.Equal(t, expectedResult, actualResult)\n    }\n\n As you see here after injecting playerService of playerController with mock object, we are calling the playerController.GetPlayer and simulate request all the way from the router.\n\n     req := httptest.NewRequest(\"GET\", \"http://localhost:8080/getScore/Rafael/vs/Serena\", nil)\n     w := httptest.NewRecorder()\n\n     r := chi.NewRouter()\n     r.HandleFunc(\"/getScore/{player1}/vs/{player2}\", playerController.GetPlayerScore)\n\n     r.ServeHTTP(w, req)\n\nAnd assert the result by using testify assertion library\n\n    assert.Equal(t, expectedResult, actualResult)\n\n----------\n\n[Circuit Breaker](https://irahardianto.github.io/service-pattern-go/#circuit-breaker)\n-------\n\nBuilding a distributed system we should really think that everything is not reliable, networks could breaks, servers could suddenly crash, even your 100% unit-tested app could be the root cause of the problems.\n\nWith that in said, when designing distributed system we should keep that in mind, so when some of our system is down, it won't take the whole system. Circuit breaker is a pattern with which we could design our system to be fault-tolerant and can withstand one or more service failure. It should be wrapping all call outside application ex: db call, redis call, api call.\n\nEssentially circuit breaker works just like electrical circuit breakers, nothing fancy here, the only different is when the breaker is tripped it can be automatically closed when the downstream service is responding properly as described in the picture below.\n\n![circuit breaker](https://cdn.pbrd.co/images/GKpFVb1.png)\n\nIn our case, we will be using hystrix-go, it is a go port from Netflix's hystrix library, how it works is essentially the same, even hystrix-go supports turbine along with its hystrix dashboard, but in my case, I rather use the datadog plugins, since we are using datadog to monitor our system.\n\nFor the sake of SOLID principles implementation in our codebase, we will add hystrix-go to our PlayerRepository leveraging decorator pattern, this will maintain our base repository implementation, the one that calls database, clean from modification and we will create its extension which is named PlayerRepositoryWithCircuitBreaker. This is the O part of SOLID which stands for Open for extension, Close for modification.\n\n\nIf you recall we inject our PlayerService with PlayerRepositoryWithCircuitBreaker and the original PlayerRepository wrapped inside.\n\n\tplayerService.PlayerRepository = \u0026repositories.PlayerRepositoryWithCircuitBreaker{playerRepository}\n\n\nBase PlayerRepository implementation :\n\n\ttype PlayerRepository struct {\n      interfaces.IDbHandler\n\t}\n\n    func (repository *PlayerRepository) GetPlayerByName(name string) (models.PlayerModel, error) {\n\n      row, err :=repository.Query(fmt.Sprintf(\"SELECT * FROM player_models WHERE name = '%s'\", name))\n      if err != nil {\n        return models.PlayerModel{}, err\n      }\n\n      var player models.PlayerModel\n\n      row.Next()\n      row.Scan(\u0026player.Id, \u0026player.Name, \u0026player.Score)\n\n      return player, nil\n\t}\n\nPlayerRepository extension implementation :\n\n    type PlayerRepositoryWithCircuitBreaker struct {\n      PlayerRepository interfaces.IPlayerRepository\n    }\n\n    func (repository *PlayerRepositoryWithCircuitBreaker) GetPlayerByName(name string) (models.PlayerModel, error) {\n\n      output := make(chan models.PlayerModel, 1)\n      hystrix.ConfigureCommand(\"get_player_by_name\", hystrix.CommandConfig{Timeout: 1000})\n      errors := hystrix.Go(\"get_player_by_name\", func() error {\n\n        player, _ := repository.PlayerRepository.GetPlayerByName(name)\n\n        output \u003c- player\n        return nil\n      }, nil)\n\n      select {\n      case out := \u003c-output:\n        return out, nil\n      case err := \u003c-errors:\n        println(err)\n        return models.PlayerModel{}, err\n      }\n    }\n\nBasically PlayerRepositoryWithCircuitBreaker implement the same interface as PlayerRepository, IPlayerRepository\n\n    type IPlayerRepository interface {\n      GetPlayerByName(name string) (models.PlayerModel, error)\n    }\n\n\nAs you see here, it is very easy to implement hystrix-go circuit breaker, you just need to wrap your db call inside hystrix if the timeout reached, the circuit breaker will be tripped and all calls to database will be halt, error will be returned instead for future call until db service is up and healthy.\n\n\nCheers,\nM. Ichsan Rahardianto.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firahardianto%2Fservice-pattern-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Firahardianto%2Fservice-pattern-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firahardianto%2Fservice-pattern-go/lists"}