I made a simple REST API with Go in my previous article. That was without any database. We are going to create a similar REST API to handle articles with a MySQL database in this article. There is no need to use any third library such as Mux at this API.
MySQL
MySQL is an open-source relational database management system. Its name is a combination of "My", the name of co-founder Michael Widenius's daughter, and "SQL", the abbreviation for Structured Query Language.
A relational database organizes data into one or more data tables in which data types may be related to each other; these relations help structure the data. SQL is a language programmers use to create, modify and extract data from the relational database, and control user access to the database.
Installing MySQL to local for development is a little complicated. We can use the Docker image of MySQL as the easiest way. It also comes with Adminer as a user interface to manage databases.
Let's create a database. As an example, let's create a database for articles or a blog. Go to Adminer, create a database, and create a table for articles.
We can check the columns of the database by this syntax.
1
SHOWCOLUMNSFROMarticles;
We created a field for ID with an unsigned integer type as it would not contain negative numbers, a field for title with 64 maximum characters, and a field for content that would contain a text. They are mandatory fields.
Let's create dummy data for articles. You can create as many records as you want. I suggest at least 10 records. The syntax below is an example.
1
INSERTINTO`articles`(`id`,`title`,`content`)VALUES(1,'The First Article','Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
Go
Let's code the GoLang part. We only need a Go file for this tutorial. Simple right?
We tried to connect to MySQL and checked whether it is connected or not by pinging it. In the code above, we have "root" as a user and password, connect to MySQL on localhost, and use the database named "go_database". Go to https://github.com/go-sql-driver/mysql for more information. Remember, we need to store sensitive information on the env file for production.
Next, let's create functions to handle CRUD operations.
funcindex(whttp.ResponseWriter,r*http.Request){rows,err:=db.Query(`SELECT * FROM articles;`)iferr!=nil{log.Fatal(err)}deferrows.Close()forrows.Next(){var(idinttitlestringcontentstring)err=rows.Scan(&id,&title,&content)iferr!=nil{log.Fatal(err)}articles=append(articles,article{id,title,content})}response,err:=json.Marshal(articles)iferr!=nil{log.Fatal(err)}ifresponse!=nil{w.Header().Set("Content-Type","application/json")w.Write(response)}}
funcread(whttp.ResponseWriter,r*http.Request,keyint){rows,err:=db.Query(`SELECT * FROM articles WHERE id = ?`,key)iferr!=nil{log.Fatal(err)}deferrows.Close()var(idinttitlestringcontentstring)forrows.Next(){err=rows.Scan(&id,&title,&content)iferr!=nil{log.Fatal(err)}}response,err:=json.Marshal(article{id,title,content})iferr!=nil{log.Fatal(err)}iftitle!=""&&content!=""{w.Header().Set("Content-Type","application/json")w.Write(response)}else{http.Error(w,http.StatusText(http.StatusNotFound),http.StatusNotFound)}}
funcupdate(whttp.ResponseWriter,r*http.Request,keyint){varrequestarticleerr:=json.NewDecoder(r.Body).Decode(&request)iferr!=nil{http.Error(w,err.Error(),http.StatusBadRequest)return}result,err:=db.Exec("UPDATE articles SET title = ?, content = ? WHERE id = ?",request.Title,request.Content,key)iferr!=nil{log.Fatal(err)}rows,err:=result.RowsAffected()iferr!=nil{log.Fatal(err)}ifrows!=0{response,err:=json.Marshal(article{key,request.Title,request.Content})iferr!=nil{log.Fatal(err)}w.Header().Set("Content-Type","application/json")w.Write(response)}else{http.Error(w,http.StatusText(http.StatusNotFound),http.StatusNotFound)}}
Delete
1
2
3
4
5
6
7
8
9
10
11
12
13
funcdelete(whttp.ResponseWriter,r*http.Request,keyint){result,err:=db.Exec("DELETE FROM articles WHERE id = ?",key)iferr!=nil{log.Fatal(err)}rows,err:=result.RowsAffected()iferr!=nil{log.Fatal(err)}ifrows!=1{http.Error(w,http.StatusText(http.StatusBadRequest),http.StatusBadRequest)}}
Routing
Let's put this code below on the main function for routing.
Our route looks a little bit complicated because it doesn't use Mux as I mentioned earlier. But the point here is to understand how the system works.
Closing
There is also a library called GORM. It simplifies our code by creating an ORM (Object-Relational Mapping) based on the structs we have defined. Feel free to try that library. But I suggest you code the ORM exclusively.