This repository demonstrates the implementation of the Service Repository Layer Pattern in the Go programming language. The Service Repository Layer Pattern is a software architectural pattern that separates the concerns of business logic (services) from data access (repositories) in an organized and maintainable way.
- Separation of concerns: The pattern separates the business logic (services) from the data access (repositories), making the codebase more modular and easier to maintain.
This modularity is enforced via Go's implementation of interfaces, and can be found as a salient feature in both the repository and service layers.
- Testability: Each layer can be unit-tested in isolation, leading to more reliable code.
- Reusability: Services and repositories can be reused in different parts of the application.
Check out
main.go
for an implementation ofEcho
's graceful shutdown feature!
Key dependencies used in this project include:
- Echo v4 for routing and server middleware, its a great library that also supports features like authorization and context logging
- govalidator for HTTP request validation
- GORM for Postgres ORM
- testify for robust testing assertions
api/
: Holds the main application logic.common/
: Contains common utilities that all subdomains can use.user/
: The user subdomain.handler/
: Repository implementations for data access.model/
: Data models and structures used throughout the application.repository/
: Repository implementations for data access.service_test/
: Service tests in the "Testing Table" style.service/
: Service implementations containing business logic.
config/
: Configuration files for the application.migrations/
: Contains the application database migration commands.routes/
: Contains the server's routes.main.go
: The main application file, and is the entry point for the application.
📝 More subdomains will be added as the project expands.
Please note that this project was designed to be run with a Postgres database however, you may also init the project with an in-memory store to test it out.
Follow these steps to get the project up and running:
-
Clone the repository to your local machine:
git clone https://github.com/sjain93/userservice.git
-
Navigate to the project directory:
cd userservice
-
Install any required dependencies:
go get -d ./...
-
Customize the configuration files in the
config/
directory according to your needs.Note that this project uses
.env
files to configure the database. Check out the originaldotenv
project hereHere's a sample of my
.env
file that connects to my local Postgres instanceDB_USER=`YOUR USER` DB_PASSWORD=`YOUR PW` DB_NAME=`YOUR DB NAME` PORT=5432 SSL_mode=disable
-
To build and run the application with Postgres setup:
go run main.go
-
To build and run the application with an in-memory store:
go run main.go -noDB
The
noDB
flag will configure the repository layer to use a in memory map found in theconfig
package.type MemoryStore map[string]interface{}
Postman was used in the development of this API, however, with the server running, here are some cURL equivalents of HTTP calls that can be made:
curl -X POST --location 'http://localhost:8080/api/users' \
--header 'Content-Type: application/json' \
--data-raw '{
"username": "Test User",
"email": "[email protected]"
}'
curl --location 'http://localhost:8080/api/users/{{userID}}'
Note that the userID is currently implemented as a
MD5
hash of theusername
and
⚙️ OpenAPI
and Swagger
doc spec to come!
In this pattern, services encapsulate the business logic of your application, while repositories provide data access methods. You can use the services in your application's handlers or controllers to perform business operations.
Here's an example of how to use a service:
// Import the necessary packages
import (
"github.com/sjain93/userservice/api/user"
"github.com/sjain93/userservice/config"
)
// Initialize the userRepository with an in memory store
memStore := config.GetInMemoryStore()
userRepository, err := user.NewUserRepository(nil, memStore)
if err != nil {
// handle the error
}
// Initialize a service
userService := service.NewUserService(userRepository)
// Create a new user
newUser := user.User{Username: "John Doe", Email: "[email protected]"}
createdUser, err := userService.CreateUser(newUser)
if err != nil {
// Handle the error
} else {
// User created successfully
}
To run unit tests for services and repositories, use the following command:
go test ./...
⚙️ More tests to come!
Contributions are welcome! If you'd like to contribute to this project, please follow these guidelines:
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Make your changes and ensure they are properly tested.
- Submit a pull request to the
main
branch of this repository.
This project is licensed under the Apache License - see the LICENSE.md file for details.
Feel free to explore the code and adapt it to your own project's needs. Happy coding! 🚀