Skip to content

Commit

Permalink
Init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jfeng45 committed Jul 2, 2019
0 parents commit 46b6315
Show file tree
Hide file tree
Showing 48 changed files with 5,533 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions .idea/servicetmpl.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

740 changes: 740 additions & 0 deletions .idea/workspace.xml

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Jin Feng

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Service Template

This is a project for me to figure out what is the best program layout for a business Microservice project in GRPC and Go. This is not the final version, which will supports transaction. Adding transaction will bring more complex into the project. In case there is no need for transaction, you can use it as the project template. It also doesn't expose the service through GRPC interface. For most people, I do recommend the full featured version [here](link).

##How to use this project
This project is best to be used as a starting point when creating a business gRPC Microservice project. It already has rich functionality to build in and is working, so there is no need to start from scratch. The purpose of it is not including many functions into it, but to build a flexible foundation, which can be extended easily. When I design and build the project, I followed SOLID design in object-oriented programing and Go's concise coding style, so it can be used as a living example of application design and coding style when you try to enforce it in your organization or your code. You may have different different design and coding style with what I have here, it is easy to change it to fit into your needs.

## Use as a template to start a service project
### Functional Feature:
1. Support different implementation of database by changing configuration file ( Currently it supports MySQL and CouchDB) (The database can be SQL and NoSQL)
2. Support different implementation of logging lib by changing configuration file ( Currently it supports ZAP and Logrus)( The logger lib need to support common interface similar to ZAP and Logrus)
3. Support business level transaction inside a service without database transaction code in business layer( it doesn't suppose nested transaction or transaction across multiple Microservice)
4. Using Dependency Injection to create concrete types and wire the whole application together.
5. Application configurations are saved in yaml file and can be changed easily.

### Design Feature:
##### 1. Programming on interface
Access outside functions through interface
Has three layer: use case, model and persistence. Each layer access other layer through interface ( Except for model layer, which doesn't need interface)
##### 2. Create concrete type through Dependency Inject by using factory method pattern
##### 3. Minimize Dependency
Dependency between different layers is only on interface ( except for model, which doesn't have interface)
Interface is defined in top level package and separated from concrete type.
Each concrete type is defined in a separate sub-package and file
##### 4. Function Isolation
Isolate different layer by package and file
Isolate each use case by package
Isolate each implementation ( for example database implementation) by package
##### 5. Open-closed principle
whenever a new feature is added, instead modify existing code, try to add new code


### Coding Style:
1. No use of package level variable except in "appcontainer" package
2. Minimize use of constant
Constants are read-only global variables, even though they are better than mutable ones, still should be restricted.
Basically, functions should encapsulate itself.
3. Log full stack trace for error
4. Errors are only handled on top level ( All other levels should only add information and propagate error to upper level)
5. separation of concerns
business logic, functional requirements (For example, retry, timeout, transaction) and technical implementation ( for example, database, logger ) are different concerns and shouldn't be mixed in one piece of code.
6. Naming Convention
function or block level variable should be named according to Go's concise naming convention, but type or interfaces shouldn't. For them, readability overweight concise, you should tell what it for from it's name.

## Getting Started

### Installation and Setting Up

Don't need to follow all steps in this section to get the code to work. The simplest way is to get the code from github and run it. However, it will throw exception when accesses database. So, I'd recommend you install at least one database ( MySQL is better), then most part of the code will work.

#### Download Code

```
go get github.com/jfeng45/sericeconfig
```

#### Set Up MySQL

There are two database implementations, MySQL and CouchDB, but most functions are implemented in MySQL. You'd better install at least one of them.
```
Install MySQL
run SQL script in script folder to create database and table
```
#### Install CouchDB

The code works fine without it. This part just shows the feature of switching database by changing configuration.

Installation on [Windows](https://docs.couchdb.org/en/2.2.0/install/windows.html)

Installation on [Linux](https://docs.couchdb.org/en/2.2.0/install/unix.html)

Installation on [Mac](https://docs.couchdb.org/en/2.2.0/install/mac.html)

CouchDB [Example](https://github.com/go-kivik/kivik/wiki/Usage-Examples)

#### Set up CouchDB

```
Access Fauxton through broswer: http://localhost:5984/_utils/# (login with: admin/admin)
Create new database "service_config" in Fauxton
Add the following document to database ( "_id" and "_rev" are generated by database, no need to change it)
{
"_id": "80a9134c7dfa53f67f6be214e1000fa7",
"_rev": "4-f45fb8bdd454a71e6ae88bdeea8a0b4c",
"uid": 10,
"username": "Tony",
"department": "IT",
"created": "2018-02-17T15:04:05-03:00"
}
```
#### Install Cache Service (Another Microservice)

Without it, only calling another Microservice piece won't work, the rest of code works just fine. Please follow instructions in [reservegrpc](https://github.com/jfeng45/reservegrpc) to set up the service.

###S tart Application

#### Start MySQL Server
```
cd [MySQLroot]/bin
mysqld
```

#### Start CouchDB Server
```
It should already been started
```
#### Start Cache Service

Please follow instructions in [reservegrpc](https://github.com/jfeng45/reservegrpc) to start the server.

#### Run main
In "main.go", under main() function, there are two functions "testMySql()" ( which reads configurations from "configs/appConifgDev.yaml") and "testCouchDB()" which reads from "configs/appConifgProd.yaml") to test MySQL and CouchDB separately.
```
cd [rootOfProject]/cmd
go run main.go
```
## License

[MIT](LICENSE.txt) License



46 changes: 46 additions & 0 deletions adapter/cacheclient/cacheClient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Package cacheclient is the wrapper around the thrid party gRPC Cache Microservice.
// It encapsulates the logic to call outside service, to make it transparent to the business logic layer.

package cacheclient

import (
"context"
pb "github.com/jfeng45/servicetmpl/adapter/cacheclient/generatedclient"
"github.com/jfeng45/servicetmpl/tools"
"google.golang.org/grpc"
)

// CacheDataGrpc represents the gRPC connection handler
type CacheDataGrpc struct {
Conn grpc.ClientConn
}

// getCacheClient creates a gRPC client
func getCacheClient(conn grpc.ClientConn) pb.CacheServiceClient {
return pb.NewCacheServiceClient(&conn)
}

// Get handles call to Get function on Cache service
func (cdg CacheDataGrpc) Get(key string) ([]byte, error) {
cacheClient := getCacheClient(cdg.Conn)
resp, err := cacheClient.Get(context.Background(), &pb.GetReq{Key: key})
if err != nil {
return nil, err
} else {
return resp.Value, err
}
}

// Store handles call to Store function on Cache service
func (cdg CacheDataGrpc) Store(key string, value []byte) error {
cacheClient := getCacheClient(cdg.Conn)
ctx := context.Background()
_, err:= cacheClient.Store(ctx, &pb.StoreReq{Key:key,Value:value})

if err != nil {
return err
} else {
tools.Log.Debug("store called")
}
return nil
}
Loading

0 comments on commit 46b6315

Please sign in to comment.