# README
REST API in Go
Disclaimer: This is a practice project that follows the tutorial How To Build a Complete API In Golang (Docker, JWT, MySQL)
Table of Contents
- STEP 0: Initialize Project
- STEP 1: API Server
- STEP 2: Database
- STEP 3: Environment Variables Sourcing
Third-Party Dependencies
go get -u github.com/gorilla/mux
go get -u github.com/go-sql-driver/mysql
STEP 0: Initialize Project
- Choose a directory on your local machine (e.g.
github
). Create a new directory (e.g.rest-api-go-practice
). Go into this newly created directory.
cd /path/to/github/
mkdir rest-api-go-practice
cd rest-api-go-practice
- Initialize a Go module within this directory.
go mod init github.com/username/rest-api-go-practice // go mod init <module-path>
NOTE: github.com/username/
is a part of the module path for Go to manage. It is NOT creating new folders (github.com
, username
) on your local machine. Rather, github.com/username/rest-api-go-practice
is used within the Go ecosystem to help Go uniquely identify this project (aka module). Because domain names (e.g. github.com
) are unique on the Internet, using this convention ensures global uniqueness of this module path. If you are linking the project to a remote repository hosted on GitHub, it is the common practice to use the full GitHub path github.com/<username>/<project-name>
as Go module path to be the unique identifier. Two advantages of doing so: 1). using domain name ensures global uniqueness. 2). helps other developers easily find the source repository on GitHub.
- Create a new repository on Github. The repository name should be the same as
rest-api-go-practice
. Link the local project to the remote repository by following the instructions provided by GitHub.- add and edit
.gitignore
- add
README.md
- add and edit
STEP 1: API Server
project/
├── main.go
└── api.go
└── APIServer <struct>
├── NewAPIServer() <constructor>
└── Serve() <method>
STEP 2: Database
project/
├── main.go
├── api.go
├── store.go
│ ├── Store <interface>
│ │ └── CreateUser()
│ └── Storage <struct>
│ ├── NewStore() <constructor>
│ └── CreateUser() <method>
└── db.go
└── MySQLStorage <struct>
├── NewMySQLStorage() <constructor>
└── Init() <method>
STEP 3: Environment Variables Sourcing
project/
├── main.go
├── api.go
├── store.go
├── db.go
└── config.go
├── Config <struct>
├── Envs <Config-type global variable>
├── initConfig() <constructor>
└── getEnv()
- Pause for a second! Let's be clear about the workflow of the main program!
- First, it creates a
mysql.Config
struct, which holds the configuration for connecting to a MySQL database. The configuration values are taken from theEnvs
variable, which holds environment variables. TheNet
field is set to"tcp"
, indicating that the connection to the MySQL server should be made over TCP.AllowNativePasswords
is set totrue
, which allows the use of the native MySQL password authentication method.ParseTime
is set totrue
, which tells the driver to parseDATE
andDATETIME
columns intotime.Time
values. - Next, it calls
NewMySQLStorage(cfg)
, which creates a newMySQLStorage
object. This object is responsible for interacting with the MySQL database. It uses the configuration provided to establish a connection to the database. - The
Init
method of theMySQLStorage
object is then called to initialize the database. If there's an error during this process, the application will log the error and exit. - After the database has been initialized, a new
Store
is created withNewStore(db)
. ThisStore
object is responsible for performing operations on the database. - Finally, a new
APIServer
is created withNewAPIServer(":3000", store)
. This server is configured to listen on port 3000 and uses theStore
for its database operations. TheServe
method is then called to start the server and begin listening for incoming HTTP requests.
- First, it creates a
func main() {
cfg := mysql.Config{
User: Envs.DBUser,
Passwd: Envs.DBPassword,
Addr: Envs.DBAddress,
DBName: Envs.DBName,
Net: "tcp",
AllowNativePasswords: true,
ParseTime: true,
}
// MySQL storage configuration
sqlStorage := NewMySQLStorage(cfg)
// Initialize the database
db, err := sqlStorage.Init()
if err != nil {
log.Fatal(err)
}
// Initialize the store
store := NewStore(db)
// Inject the store into the API server
api := NewAPIServer(":3000", store)
api.Serve()
}