Docker Golang GraphQL Build An Api And Deployment on DigitalOcean

In this tutorial we will make an api backend using Golang + GraphQL to getting start i will use use GraphQL generate
Features:
- Learn to use Golang build backend1 Api
- Learn to use GraphQL gen
- Use GraphQL technology
- Learn to use Docker and deployment
- Learn to use Golang Mysql Driver and Modeling data
- Use Redis for caching layer
- DigitalOcean Ubuntu Deployment use Docker
Video Tutorial
Sample Schema
type User{
id: ID!
first_name: String!
last_name: String!
email: String!
created_at: Int!
updated_at: Int!
}
input NewUser{
first_name: String!
last_name: String!
email: String!
password: String!
}
type Query {
users: [User]!
}
type Mutation {
createUser(input: NewUser!): User!
}
Resolve
package dexp
import (
"context"
"time"
) // THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
type Resolver struct{}
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
}
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
type mutationResolver struct{ *Resolver }
func (r *mutationResolver) CreateUser(ctx context.Context, input NewUser) (*User, error) {
// insert into our database
now := int(time.Now().Unix())
u := &User{
FirstName: input.FirstName,
LastName: input.LastName,
Email: input.Email,
Password: input.Password,
CreatedAt: now,
UpdatedAt: 0,
}
err := u.Create()
if err != nil{
return nil, err
}
return u, nil
}
type queryResolver struct{ *Resolver }
func (r *queryResolver) Users(ctx context.Context) ([]*User, error) {
return GetAllUsers()
}
User Model
package dexp
type User struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Password string `json:"password"`
CreatedAt int `json:"created_at"`
UpdatedAt int `json:"updated_at"`
}
func GetAllUsers() ([]*User, error){
var result []*User
rows, err := DB.Query("SELECT id, first_name, last_name, email, password, created_at, updated_at FROM `users`")
if err != nil{
return nil, err
}
defer rows.Close() // important
for rows.Next() {
var u User
err = rows.Scan(&u.ID, &u.FirstName, &u.LastName, &u.Email, &u.Password, &u.CreatedAt, &u.UpdatedAt)
if err != nil{
return nil, err
}
result = append(result, &u)
}
return result, nil
}
func (u *User) Create() error {
// user save to our db get id
result, err := DB.Exec("INSERT INTO `users` (first_name, last_name, email, password, created_at, updated_at) VALUES(?, ?, ?, ?, ?, ?)", u.FirstName, u.LastName, u.Email, u.Password, u.CreatedAt, u.UpdatedAt)
if err != nil {
return err
}
lastId, err := result.LastInsertId()
if err != nil {
return err
}
u.ID = int(lastId)
return nil
}
Custom Running local Development
create ./run.sh
#!/usr/bin/env bash
export PORT=3001
export MYSQL_URL="user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=true&sql_mode=ansi"
export REDIS_URL=redis://localhost:6379
go run ./server/server.go
Custom Generate GraphQL
create file ./gen.sh
#!/usr/bin/env bash
mv resolver.go resolver.old
go run github.com/99designs/gqlgen # generate graphQL
cp resolver.go resolver.go.new
git merge-file resolver.go resolver.go resolver.old
Build Go project
#!/usr/bin/env bash
cd ./server
GOOS=linux GOARCH=amd64 go build -v -o ../docker/dexp
Inside ./docker folder contain two files
Docker-compose.yml
version: '3.1'
services:
server:
build: ./
container_name: server
restart: always
image: dexp
ports:
- 8080:8080
links:
- mysql
- redis
environment:
- "PORT=8080"
-"MYSQL_URL=root:pass@tcp(mysql:3306)/dbname?parseTime=true&sql_mode=ansi"
- "REDIS_URL=redis://redis:6379"
mysql:
container_name: mysql
restart: always
image: mysql:5.7
environment:
MYSQL_DATABASE: 'dbname'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- '3306:3306'
redis:
image: "redis:alpine"
container_name: redis
ports:
- 6379:6379
Dockerfile
FROM alpine
COPY ./dexp /bin/
EXPOSE 5001
ENTRYPOINT [ "/bin/dexp" ]