-
Notifications
You must be signed in to change notification settings - Fork 45
How to
This wiki walks you through how to use the Atlas-cli and some toolkit features to create a sample project. The project will be a simpler version of atlas-contacts-app. Please, view the atlas-contacts-app for a more complete example.
- Create a contacts application that allows you to save and retrieve contacts from a database
- Learn how to use the bootstrap tool and flags
- Understand the project structure and how to add new methods
- Usage of the generated Makefile
- How to run your application and send requests
The following steps will install the atlas
binary to your $GOBIN
directory.
$ go get github.com/infobloxopen/atlas-cli/atlas
You're all set! Alternatively, you can clone the repository and install the binary manually.
$ git clone https://github.com/infobloxopen/atlas-cli.git
$ cd atlas-cli
$ make
The atlas-cli tool and generated apps also depend on the golang dep tool. On OSX it can be installed like this:
$ brew install dep
Rather than build applications completely from scratch, you can leverage the command-line tool to initialize a new project. This will generate the necessary files and folders to get started.
$ atlas init-app -name=my-application
$ cd my-application
Here's the full set of flags for the init-app
command.
Flag | Description | Required | Default Value |
---|---|---|---|
name |
The name of the new application | Yes | N/A |
db |
Bootstrap the application with PostgreSQL database integration | No | false |
gateway |
Initialize the application with a gRPC gateway | No | false |
health |
Initialize the application with internal health checks | No | false |
pubsub |
Initialize the application with a atlas-pubsub example | No | false |
registry |
The Docker registry where application images are pushed | No | "" |
You can run atlas init-app --help
to see these flags and their descriptions on the command-line.
-
Run bootstrap command to create project
atlas init-app -name "contacts-app" -gateway -db -health
This will create a project with the name "contacts-app" that will contain a grpc gateway proxy which will allow your application to call REST endpoints, a database, and health checks.
-
Navigating the project
Directory Description cmd
Contains config, gateway, and server files db
Empty when initialized but needs to include database migration files if needed and test fixtures deploy
Empty when initialized but needs to include kubernetes manifest files docker
Dockerfiles for the application pkg
Contains the proto file and the autogenerated sources by protobuf (Majority implementation goes here) vendor
Local copies of external dependencies to satisfy imports of those dependencies Gopkg.toml
Initialized by dep (dependency management tool for Go) contains all dependencies for your project Makefile
Contains helpful commands to get your application running README.md
Readme template for your project
- Understanding Configuration
- Generated atlas projects use viper, a complete configuration solution that allows an application to run from different environments.
- For a more detailed summary look at configuration
- All the configurations for this project exist in
cmd/server/config.go
- By default it will autogenerate everything that was provided when bootstrapping the application
- Since we passed the db flag we want to ensure that we have a postgres server running and have created a
contacts_app
database for our application (CREATE DATABASE contacts_app;
) - Make any necessary changes inside
config.go
to ensure that database adresss and port is correct. - Note: atlas-cli auto generates a db for postgres that uses protoc-gen-gorm if you want to use another RDB you would have to implement it yourself. d
- Since we passed the db flag we want to ensure that we have a postgres server running and have created a
- Running sample generated service
- Each project gets created with a sample service called
version
- All services are created in
pkg/pb/service.proto
- To run the project make sure your in the project direcory and run:
go run cmd/server/*.go
- This will run your project in localhost:8080/v1/contacts-app (based on config.go)
- To call service:
curl localhost:8080/contacts-app/v1/version
- You will receive a response as follows:
{"version":"0.0.1"}
- If you don't receive this please check your config.go and make sure you using the correct address.
- Each project gets created with a sample service called
- Adding a new service
- To add a new service we need to define the message and service inside the proto file.
- Atlas projects use protocol buffers to define how the data should be structured
- Lets first create a definition for a Contact object:
// Contact represents a particular person in an contacts list. message Contact { // The id associated to the person int64 id = 1; // The first name of the person. string first_name = 2; // The middle name of the person. string middle_name = 3; // The last name of the person. string last_name = 4; // The person's primary email. string email = 5; // The home address of the person. string home_address = 6; }
- Next, we need to create a service which needs a few things
- A request
- A response
- Service definition
- Service implementation
- First, we need to define the response and request for our service. For our first example we will create a service that doesn't depend on a databse. We will create a service that will tell return your first name in reverse.
message ReverseRequest { Contact payload = 1; } message ReverseResponse { string result = 1; }
- Next, we need to define our service definition
- Since we are using a grpc gateway proxy we need to define the endpoint for our service using 'option (google.api.http)'
- For more info look at: GRPC Gateway
rpc Reverse (ReverseRequest) returns (ReverseResponse) {å option (google.api.http) = { post: "/reverse" body: "payload" }; }
- Regenerating the protobuf
- Whenever we update our proto file we want to update our generated protobuf files to reflect the changes
make protobuf
- Implementing new services
- Now that we have added a new service we want to write the implementation for it
- Inside pkg/svc/zserver.go add the following:
// Reverse returns the first name in reverse func (server) Reverse(ctx context.Context, req *pb.ReverseRequest) (*pb.ReverseResponse, error) { r := []rune(req.Payload.FirstName) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return &pb.ReverseResponse{Result: string(r)}, nil }
- Run your project again (
go run cmd/server/*.go
) - Check service:
curl -X POST http://0.0.0.0:8080/contacts-app/v1/reverse -H /v1/reverse -d '{ "first_name": "John", "last_name": "Doe", "email": "johndoe@gmail.com" }'
- Congratulations for creating your first service!
- Adding the database layer
-
Atlas Projects are recommended to use protoc-gen-gorm a protobuf compiler plugin designed to generate GORM models and APIs for simple object persistence tasks.
-
When using protoc-gen-gorm we want to remember the following things:
- Add
option (gorm.opts).ormable = true;
to the messsages and services that you want to be auto generated. - When adding the gorm model we need to add the new server inside the zserver.go file and update the grpc.go to include that server.
- Add
-
Update your Contacts definition as below to generate gorm models.
// Contact represents a particular person in an contacts list. message Contact { option (gorm.opts).ormable = true; // The id associated to the person int64 id = 1; // The first name of the person. string first_name = 2; // The middle name of the person. string middle_name = 3; // The last name of the person. string last_name = 4; // The person's primary email. string email = 5; // The home address of the person. string home_address = 6; }
-
Next, we want to add all the CRUD definitions in the proto file
message CreateContactRequest { Contact payload = 1; } message CreateContactResponse { Contact result = 1; } message ReadContactRequest { int64 id = 1; } message ReadContactResponse { Contact result = 1; } message UpdateContactRequest { Contact payload = 1; } message UpdateContactResponse { Contact result = 1; } message DeleteContactRequest { int64 id = 1; } message DeleteContactResponse {}
// Inside service add: option (gorm.server).autogen = true; // Use this method to create a contact information. rpc Create (CreateContactRequest) returns (CreateContactResponse) { option (google.api.http) = { post: "/contacts" body: "payload" }; } // Use this method to read a contact information by identifier. rpc Read (ReadContactRequest) returns (ReadContactResponse) { option (google.api.http) = { get: "/contacts/{id}" }; } // Use this method to update a contact information. rpc Update (UpdateContactRequest) returns (UpdateContactResponse) { option (google.api.http) = { put: "/contacts/{payload.id}" body: "payload" additional_bindings: { patch: "/contacts/{payload.id}" body: "payload" } }; } // Use this method to delete a particular contact. rpc Delete (DeleteContactRequest) returns (DeleteContactResponse) { option (google.api.http) = { delete: "/contacts/{id}" }; option (gorm.method).object_type = "Contact"; }
-
Update the server in zserver.go
func NewContactsServer(database *gorm.DB) (pb.ContactsAppServer, error) { return &contactsServer{&pb.ContactsAppDefaultServer{DB: database}}, nil } type contactsServer struct { *pb.ContactsAppDefaultServer }
-
Change the basic server to your specific server inside grpc.go
// old: s, err := svc.NewBasicServer(db) s, err := svc.NewContactsServer(db)
-
Lastly, lets create a table in our database so that we can start using our new services
CREATE TABLE contacts( id serial PRIMARY KEY, first_name VARCHAR (50) NOT NULL, middle_name VARCHAR (50), last_name VARCHAR (50) NOT NULL, email VARCHAR (260) UNIQUE NOT NULL, home_address VARCHAR (260) );
-
To test create:
curl -X POST \ http://0.0.0.0:8080/contacts-app/v1/contacts \ -H 'Content-Type: application/json' \ -d '{ "first_name": "Roman", "last_name": "Azami", "email": "romanazami@outlook.com" }'
-
- Running application
- To run locally:
go run cmd/server/*.go
- To make docker image:
make docker