Build Your First Service
This document describes the step by step about how to generate a game backend service using mykit.
Setup repository
Step 1: Login gitlab and create new project. ex: demo01
Step 2: Open the terminal and navigate to the go-workspace/src folder, at here create gitlab.nautilusgames.tech folder, then navigate to the folder that has already created, ex:
cd go-workspace/src/
mkdir gitlab.nautilusgames.tech
cd gitlab.nautilusgames.tech
Step 3: Clone and open demo01 project
git clone https://gitlab.nautilusgames.tech/demo01.git
cd demo01
code .
Init project
Run command below to init new project
mykit init --dir ~/go-workspace/src/gitlab.nautilusgames.tech/demo01 --name demo01
Note:
-
If mykit is not found, please install mykit and try again.
-
Local folder much be same with repo URL.
Project structure
After using mykit init to init new project, this produces the following structure:
demo01
├── api
│ ├── ...
│ ├── demo01_config.proto
│ ├── demo01_code.proto
│ └── demo01.proto
├── build
│ └── ...
├── cmd
│ └── main.go
├── configs
│ └── config.yaml
├── internal
│ └── server
├── package
│ └── ...
├── schema
│ ├── base.go
│ └── sample.go
├── vendor
│ └── ...
├──.dockerignore
├──.gitignore
├── ci.yaml
├── go.mod
├── go.sum
├── Makefile
└── mykit.yaml
-
api: including proto file that use to define gRPC services and the structure for the data you want to serialize.
-
configs: including config.yaml file that use to define the config of your service, that config matching with Config message structure that defines in proto file.
-
internal: using handle core logic and runs gRPC server to handle client calls.
-
schema: using to declare model database schema as a graph structure.
-
mykit.yaml: define mykit config, can change some config to support your demand, below is a example for
mykit.yamlfile.
project:
name: demo01
monorepo: false
go_package: gitlab.nautilusgames.tech/demo01
npm_package: "@marketplace/demo01"
npm_registry: gitlab.nautilusgames.tech/api/v4/projects/31/packages/npm/
extend: # extend file name
generate:
allow_custom_options: true
profiling:
port: 6060
enable: false
dockerfile: # using generate dockerfile
enable: true
ent: # using generate schema when enable is true
enable: false
command: # using generate cmd that have main.go file
enable: true
server: # using generate server
enable: true
path: internal/server
grpc_server: # using generate grpc server
enable: true
path: internal/server
grpc_gateway:
enable: false
client: # using generate client that can use to test API if new it
enable: true
path: pkg/client
helm:
enable: false
proto: # using declare proto files that you want to generate
go:
- demo01.proto
- demo01_config.proto
- demo01_code.proto
js: # allow build npm package using grpc-web
- demo01.proto
- demo01_code.proto
js_connect: # allow build npm package for connect-grpc
- demo01.proto
- demo01_code.proto
imports: # optional
grpc_log:
enable: false
Working with gRPC
Create new proto file
Step 1: At ./api folder create new proto file, such as demo01_model.proto
Step 2: Define protocol buffer messages
Ex:
message User {
string user_name = 1;
int age = 2;
}
Step 3: Generate proto message
The first step, need add demo01_model.proto into mykit.yaml files.
Ex:
project:
...
extend: # extend file name
generate:
...
proto:
go:
...
- demo01_model.proto
js:
...
- demo01_model.proto
js_connect:
...
- demo01_model.proto
imports: # optional
grpc_log:
enable: false
Note:
-
At
go typeneed add proto file. -
At
js, js_connect typeonly add if want to share model for client.
The second step, generate proto file.
mykit generate go
Define gRPC service
Step 1: Define gRPC services in ordinary proto files, with RPC method parameters and return types specified as protocol buffer messages.
./api/demo01.proto
service Demo01 {
rpc Hello(HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string user_name = 1;
}
message HelloReply {
string message = 1;
}
Step 2: Generate proto file
Run command below to generate proto file.
mykit generate go
Step 3: Implement server
./internal/server/demo01/grpc_demo01_hello.go
func (s *demo01Server) Hello(ctx context.Context, request *demo01.HelloRequest) (*demo01.HelloReply, error) {
if err := request.Validate(); err != nil {
return nil, err
}
if request.UserName == "" {
return nil, fmt.Errorf("user not found")
}
return &demo01.HelloReply{
Message: fmt.Sprintf("%s%s", "hello ", request.GetUserName()),
}, nil
}
Step 4: Run server
Input command below to run demo01 server. You can use Postman or BloomRPC to call API.
go run cmd/main.go -c ./configs/config.yaml
Working with database
Init schema
We will use ent to generate database. Ent is a simple, yet powerful entity framework for Go, that makes it easy to build and maintain applications with large data-models.
Step 1: To generate schema, go to mykit.yaml file and set enable ent is true.
generate:
...
ent:
enable: true
...
Step 2: Define schema model
./schema/user.go
type User struct {
ent.Schema
}
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int64("id"),
field.String("user_name"),
field.Int64("age"),
}
}
func (User) Mixin() []ent.Mixin {
return []ent.Mixin{
Base{},
}
}
Step 3: Generate database
Go to ./pkg/doc.go file, click run go generate to generate schema. If is not found doc.go file, run below command to generate database.
mykit generate go
Config database
Step 1: Add database config and database config value
At ./api/demo01_config.proto file, add database config. Ex:
import "database/api/database.proto"; // need to import
message Config {
...
greyhole.database.Database database = 1 [(validate.rules).message.required = true];
...
}
At ./configs/config.yaml file, add database value.
The environment variable value will be set at aws secret.
database:
auth_method: ${DATABASE_AUTH_METHOD} # DATABASE_AUTH_METHOD_AWS_IAM
host: ${DATABASE_HOST}
port: 3306
name: ${DATABASE_NAME}
username: ${DATABASE_USERNAME}
aws_region: ${DATABASE_AWS_REGION}
debug: false
tracing_enabled: true
max_idle_conns: 5
max_open_conns: 5
conn_max_life_time: 3 # minutes
conn_max_idle_time: 3 # minutes
Step 2: Generate proto
Introduction to the gRPC-Gateway and How to do it
Introduction to the gRPC-Gateway
We all know that gRPC is not a tool for everything. There are cases where we still want to provide a traditional HTTP/JSON API. The reasons can range from maintaining backward-compatibility to supporting programming languages or clients not well supported by gRPC. But writing another service just to expose an HTTP/JSON API is quite a time consuming and tedious task.
The gRPC-Gateway is a plugin of the Google protocol buffers compiler protoc. It reads protobuf service definitions and generates a reverse-proxy server which translates a RESTful HTTP API into gRPC. This server is generated according to the google.api.http annotations in your service definitions.
This helps you provide your APIs in both gRPC and HTTP/JSON format at the same time.
Working with gRPC-gateway
Step 1: Add the gateway server
Continue modify the ./api/demo01.proto file to add the gateway server changes. The new contents look like this:
./api/demo01.proto
import "google/api/annotations.proto"; // need to import
service Demo01 {
rpc Hello(HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/api/v1/demo01/hello"
};
}
}
message HelloRequest {
string user_name = 1;
}
message HelloReply {
string message = 1;
}
Step 2: At mykit.yaml file, set enable generate grpc_gateway and http_server.
generate:
...
http_server:
enable: true
grpc_gateway:
enable: true
Step 3: Add http listener
At ./api/demo01_config.proto file, add http_listener:
import "validate/validate.proto";
import "logger/api/logger.proto";
message Config {
...
greyhole.carbon.Listener http_listener = 1 [(validate.rules).message = { required: true }];
}
At ./configs/config.yaml file, add http_listener value:
...
http_listener:
tcp:
address: 0.0.0.0
port: 8081
secure: false
...
Step 4: Generate proto
Step 5: Test API by postman or bloomRPC, try with gRPC request and HTTP request.