Go (aka Golang) is a relatively new and hot language in the programming community in Vietnam. With high performance (running faster than Node.JS, PHP, Ruby, … and just a little slower than C / C ++) plus a simple, bright syntax, Golang helps programmers can build systems. High performance backend system easier. Listen, a well-known programming center in Hanoi has changed the backend part of the entire website from Node.JS to Golang. Today, let’s learn the basics of writing servers with Golang.
1. Architecture
Programming web server with pure Golang, we will use net / http package to create server (listen port, process request, create response …). Anyone who has programmed Node.JS finds it quite similar to how we use the http module inside Node.JS.
The net / http library provides us with a stream of data processing as shown below.
The request from the client to the original server will have to go through a component called Multiplexer . The multiplexer analyzes the request (depending on the url or method) and passes it to the appropriate Handler for further processing. Handlers will be functions that call Database , handle request logic according to the request and return data to the Template to display (Template engine as in Node.JS is ejs or jade …). Finally, Multiplexer will return the response to the client.
2. Hello world
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token comment">// hello.go</span> <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"net/http"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> http <span class="token punctuation">.</span> <span class="token function">HandleFunc</span> <span class="token punctuation">(</span> <span class="token string">"/"</span> <span class="token punctuation">,</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> w http <span class="token punctuation">.</span> ResponseWriter <span class="token punctuation">,</span> r <span class="token operator">*</span> http <span class="token punctuation">.</span> Request <span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintf</span> <span class="token punctuation">(</span> w <span class="token punctuation">,</span> <span class="token string">"Hello, you've requested: %sn"</span> <span class="token punctuation">,</span> r <span class="token punctuation">.</span> URL <span class="token punctuation">.</span> Path <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> http <span class="token punctuation">.</span> <span class="token function">ListenAndServe</span> <span class="token punctuation">(</span> <span class="token string">":3000"</span> <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- The first 2 lines for those who have learned Golang will not be strange. That is including the main package and importing 2 libraries, fmt and net / http.
- The
HandleFunc
function of thenet/http
library takes two arguments, the incoming path and a function that contains two parameters.w http.ResponseWriter
is where you can edit the response when returning the client,r *http.Request
contains the information of the request that the client sends to the server. This code looks quite similar to Express JS.
1 2 3 4 | app <span class="token punctuation">.</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> <span class="token function">func</span> <span class="token punctuation">(</span> req <span class="token punctuation">,</span> res <span class="token punctuation">)</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Hello World!'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
- The last line passes two parameters with the
ListenAndServe
function to open the port, where the client can request to the server. The first parameter is the port you want to open, the second argument isnil
, the server will use the default Multiplexer innet/http
. If you want to use 3rd party Multiplexer , you can refer to gorilla / mux or http / router .
Run the file
1 2 | go run hello.go |
Open a browser and go to http: // localhost: 3000
3. Using a 3rd party Multiplexer
As mentioned in the previous section, we can use 3rd party Multiplexer for Golang server instead of default Multiplexer in net/http
library. The default multiplexer may be missing or limited at some point compared to the 3rd party. For example the complexity of obtaining params requests on urls.
Grollia / mux
Instal package grollia/mux
:
1 2 | go get -u github.com/gorilla/mux |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"net/http"</span> <span class="token string">"github.com/gorilla/mux"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> r <span class="token operator">:=</span> mux <span class="token punctuation">.</span> <span class="token function">NewRouter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> r <span class="token punctuation">.</span> <span class="token function">HandleFunc</span> <span class="token punctuation">(</span> <span class="token string">"/books/{title}/page/{page}"</span> <span class="token punctuation">,</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> w http <span class="token punctuation">.</span> ResponseWriter <span class="token punctuation">,</span> r <span class="token operator">*</span> http <span class="token punctuation">.</span> Request <span class="token punctuation">)</span> <span class="token punctuation">{</span> vars <span class="token operator">:=</span> mux <span class="token punctuation">.</span> <span class="token function">Vars</span> <span class="token punctuation">(</span> r <span class="token punctuation">)</span> title <span class="token operator">:=</span> vars <span class="token punctuation">[</span> <span class="token string">"title"</span> <span class="token punctuation">]</span> page <span class="token operator">:=</span> vars <span class="token punctuation">[</span> <span class="token string">"page"</span> <span class="token punctuation">]</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintf</span> <span class="token punctuation">(</span> w <span class="token punctuation">,</span> <span class="token string">"You've requested the book: %s on page %sn"</span> <span class="token punctuation">,</span> title <span class="token punctuation">,</span> page <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> http <span class="token punctuation">.</span> <span class="token function">ListenAndServe</span> <span class="token punctuation">(</span> <span class="token string">":3000"</span> <span class="token punctuation">,</span> r <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- The first line of the main function is to create an instance of
gorilla/mux
multiplexer, the HandleFunc function to handle the request will also call through the new multiplexer instead ofhttp
as using the default multiplexer. - The second argument of the
ListenAndServe
function also passesr
instead ofnil
as above.
http / router
Instal package http/router
:
1 2 | go get -u github.com/julienschmidt/httprouter |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"net/http"</span> <span class="token string">"github.com/julienschmidt/httprouter"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> router <span class="token operator">:=</span> httprouter <span class="token punctuation">.</span> <span class="token function">New</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> router <span class="token punctuation">.</span> <span class="token function">GET</span> <span class="token punctuation">(</span> <span class="token string">"/"</span> <span class="token punctuation">,</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> w http <span class="token punctuation">.</span> ResponseWriter <span class="token punctuation">,</span> r <span class="token operator">*</span> http <span class="token punctuation">.</span> Request <span class="token punctuation">,</span> <span class="token boolean">_</span> httprouter <span class="token punctuation">.</span> Params <span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprint</span> <span class="token punctuation">(</span> w <span class="token punctuation">,</span> <span class="token string">"Welcome!n"</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> router <span class="token punctuation">.</span> <span class="token function">GET</span> <span class="token punctuation">(</span> <span class="token string">"/hello/:name"</span> <span class="token punctuation">,</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> w http <span class="token punctuation">.</span> ResponseWriter <span class="token punctuation">,</span> r <span class="token operator">*</span> http <span class="token punctuation">.</span> Request <span class="token punctuation">,</span> ps httprouter <span class="token punctuation">.</span> Params <span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintf</span> <span class="token punctuation">(</span> w <span class="token punctuation">,</span> <span class="token string">"hello, %s!n"</span> <span class="token punctuation">,</span> ps <span class="token punctuation">.</span> <span class="token function">ByName</span> <span class="token punctuation">(</span> <span class="token string">"name"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> http <span class="token punctuation">.</span> <span class="token function">ListenAndServe</span> <span class="token punctuation">(</span> <span class="token string">":8080"</span> <span class="token punctuation">,</span> router <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- Slightly different from the 2 multiplexers above.
http/router
handles requests according to the functions corresponding to the http methods (very similar to express js). Parameters passed in the callback function are also 3 parameters, not 2 with the form. Taking params from the request is also quite sweet.
1 2 | <span class="token keyword">func</span> <span class="token punctuation">(</span> http <span class="token punctuation">.</span> ResponseWriter <span class="token punctuation">,</span> <span class="token operator">*</span> http <span class="token punctuation">.</span> Request <span class="token punctuation">,</span> Params <span class="token punctuation">)</span> |
More details on functions like POST, PUT, DELETE, … you can refer here
4. Working with the database
We will demonstrate a little demo about Golang manipulating MongoDB database management system.
First, install the mongodb package
1 2 | go get go.mongodb.org/mongo-driver |
Connect with mongodb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <span class="token comment">// database.go</span> <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"context"</span> <span class="token string">"fmt"</span> <span class="token string">"log"</span> <span class="token string">"go.mongodb.org/mongo-driver/mongo"</span> <span class="token string">"go.mongodb.org/mongo-driver/mongo/options"</span> <span class="token punctuation">)</span> <span class="token keyword">type</span> User <span class="token keyword">struct</span> <span class="token punctuation">{</span> username <span class="token builtin">string</span> password <span class="token builtin">string</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> clientOptions <span class="token operator">:=</span> options <span class="token punctuation">.</span> <span class="token function">Client</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ApplyURI</span> <span class="token punctuation">(</span> <span class="token string">"mongodb://localhost:27017/demo"</span> <span class="token punctuation">)</span> client <span class="token punctuation">,</span> err <span class="token operator">:=</span> mongo <span class="token punctuation">.</span> <span class="token function">Connect</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">TODO</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> clientOptions <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log <span class="token punctuation">.</span> <span class="token function">Fatal</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Check the connection</span> err <span class="token operator">=</span> client <span class="token punctuation">.</span> <span class="token function">Ping</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">TODO</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log <span class="token punctuation">.</span> <span class="token function">Fatal</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">}</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"Connected to MongoDB!"</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Basically connecting to the database with Golang is no different from other languages, we all need to pass MONGO_URI
and use the connect function in the mongo library to connect to the database to interact. The above code has a User
model of 2 username
and password
fields representing the data structure that will be saved in the collection
.
Run go run database.go
and the results will appear if the connection is successful
Manipulate a little with the data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <span class="token comment">// insert.go</span> <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"context"</span> <span class="token string">"fmt"</span> <span class="token string">"log"</span> <span class="token string">"go.mongodb.org/mongo-driver/mongo"</span> <span class="token string">"go.mongodb.org/mongo-driver/mongo/options"</span> <span class="token punctuation">)</span> <span class="token keyword">type</span> User <span class="token keyword">struct</span> <span class="token punctuation">{</span> username <span class="token builtin">string</span> password <span class="token builtin">string</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> clientOptions <span class="token operator">:=</span> options <span class="token punctuation">.</span> <span class="token function">Client</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ApplyURI</span> <span class="token punctuation">(</span> <span class="token string">"mongodb://localhost:27017/demo"</span> <span class="token punctuation">)</span> client <span class="token punctuation">,</span> err <span class="token operator">:=</span> mongo <span class="token punctuation">.</span> <span class="token function">Connect</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">TODO</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> clientOptions <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log <span class="token punctuation">.</span> <span class="token function">Fatal</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Check the connection</span> err <span class="token operator">=</span> client <span class="token punctuation">.</span> <span class="token function">Ping</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">TODO</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log <span class="token punctuation">.</span> <span class="token function">Fatal</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">}</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"Connected to MongoDB!"</span> <span class="token punctuation">)</span> collection <span class="token operator">:=</span> client <span class="token punctuation">.</span> <span class="token function">Database</span> <span class="token punctuation">(</span> <span class="token string">"demo"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">Collection</span> <span class="token punctuation">(</span> <span class="token string">"users"</span> <span class="token punctuation">)</span> user <span class="token operator">:=</span> User <span class="token punctuation">{</span> <span class="token string">"conglt"</span> <span class="token punctuation">,</span> <span class="token string">"sdajah1kj2h3hu23h"</span> <span class="token punctuation">}</span> insertResult <span class="token punctuation">,</span> err <span class="token operator">:=</span> collection <span class="token punctuation">.</span> <span class="token function">InsertOne</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">TODO</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> user <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log <span class="token punctuation">.</span> <span class="token function">Fatal</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">}</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"Inserted a Single Document: "</span> <span class="token punctuation">,</span> insertResult <span class="token punctuation">.</span> InsertedID <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- After successfully connecting to the mongodb, we will specify the
database
and thecollection
will interact directly with the command. If thedatabase
andcollection
not yet exist, mongo will create one for us.
1 2 | collection <span class="token operator">:=</span> client <span class="token punctuation">.</span> <span class="token function">Database</span> <span class="token punctuation">(</span> <span class="token string">"demo"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">Collection</span> <span class="token punctuation">(</span> <span class="token string">"users"</span> <span class="token punctuation">)</span> |
- The next 2 lines will call to create an instance of the struct User and then call the
InsertOne
function in the mongo library to add a new record to thecollection
.
The mongo
library provides many functions that interact with the database such as adding, editing, deleting, … Details of the usage and prototype of functions you can see in detail in GoDoc .