
This article explains how to build a secure REST API in Go with Vultr Managed Databases for MySQL. By following this guide, you'll create a Vultr Managed Database for MySQL, connect to it securely using TLS, execute CRUD (Create, Read, Update, Delete) operations with the Go MySQL client, and use the Gin Web Framework to build a REST API.
One of the most popular MySQL libraries is libmysqlclient, a C API that provides low-level access to MySQL for command-line clients, MySQL connectors, and third-party APIs. MySQL offers connectors (libraries or drivers) for other popular programming languages. These include JDBC (for Java applications), .NET, Python, Node.js, Ruby, PHP, and Perl, among others. These connectors/libraries/drivers are either built using the libmysqlclient (using C-binding provided by the programming language) or by implementing a native driver. Each approach has pros and cons.
Native drivers implement the MySQL network protocol entirely within the host language or environment. They are fast, can offer advanced functionality, and are easier for end users to build and deploy because no copy of the MySQL client libraries is needed to build the native driver components.
Using libmysqlclient offers complete compatibility with MySQL, but their feature set is limited to the interfaces exposed through libmysqlclient, and the performance may be lower (compared to native drivers) as data is copied between the native language and the MySQL API components.
Go MySQL Driver is a MySQL driver for the Go database/sql package. It is a native Go implementation that supports a rich feature set which includes:
Gin is an HTTP high-performance web framework that uses the httprouter library. Some of its key features include:
To follow the instructions in this article:
Log into your Vultr account, navigate to Add Managed Database and follow the below steps.
Choose the MySQL database engine.
You can choose from several options in the Server Type. This includes Cloud Compute, Cloud Compute High Performance - AMD or Intel, and Optimized Cloud Compute - General Purpose, Storage or Memory Optimized.
You should also select zero or more replica nodes and the cluster location. A replica node is the same server type and plan as the primary node.
This article uses a Cloud Compute server type without a replica node.
After you add a label for the database cluster, click Deploy Now to create the cluster. It will take a few minutes for the cluster to be available, and the Status should change to Running.
The Vultr MySQL Managed Database is ready for you to connect to it with a Go program.
Create a directory and switch to it:
Create a new Go module:
This will create a new
go.modfile
Create a new file main.go:
To import required Go modules, add the following to main.go file:
The following packages are imported:
database/sql - This package includes types and functions for connecting and working with a SQL database.github.com/go-sql-driver/mysql - While database/sql provides a generic interface for SQL database, you need a driver for the specific database you want to use. In this case, you are using a MySQL database and its corresponding driver. The driver is loaded anonymously (the _ alias is used in its package qualifier) and gets registered.github.com/gin-gonic/gin - Provides the Gin Web Framework supportAdd the below code to main.go file:
createTable and dropTable are queries for creating and deleting the MySQL table, respectively.init function.init functionAdd the code below to main.go file:
The init function takes care of two important things:
MYSQL_HOST, MYSQL_PORT, MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_DBNAME and MYSQL_TLS_CERT_LOCATION respectively).sql.Open). It creates a pointer to a sql.DB object that represents a pool of zero or more connections to the underlying database.main functionAdd the main function to main.go file:
The main function has been left empty as our goal (in the next section) is to ensure that you are able to connect to the MySQL database. The main function will be updated later in the article as you add the rest of the application logic.
To establish a connection with the Vultr MySQL Managed Database using your Go program, you need to get the connection details. Before continuing, you need to do the following:
Get the connection details:
username, password, host, host, port, and databaseTo download the Signed certificate, click on Download Signed Certificate and save it to a location on your local machine.
Fetch the Go module dependencies for the program:
You might get the following output:
To run the program:
If the connectivity was established, you should see the following output:
Now, you can add the rest of the application logic.
users table in MySQLThe createUser HTTP handler is used to add rows to the table.
Create a new file handler.go:
Add imports
Add imports to the handler.go file:
Add HTTP handler
To add the HTTP handler to process requests, add the code below to handler.go file:
Add create user request message
Create a new file model.go:
Add the below code to model.go file:
createUser function accepts a gin.Context object.CreateUserRequest represents the payload that contains information about the user to be created (Email and Name).ShouldBind parses the request body as JSON (since you will use the application/json Content-Type header). It decodes the JSON payload into the CreateUserRequest struct specified as a pointer.Exec is used to execute the insert query (INSERT into users (Email, Name) VALUES (?, ?); query on the database with the user name and email that was retrieved from the HTTP payload body.Location header in the HTTP response (along with the 201 Created HTTP response).UseridThe getUserWithID HTTP handler is used to retrieve user information using its id.
Add the below code to handler.go file:
Add the below code to model.go file:
getUserWithID accepts a gin.Context object.Param function.QueryRow is used to execute the SELECT * FROM users where Userid=?; query on the database with the user ID that was retrieved earlier.sql.ErrNoRows error, respond with an HTTP 404 (StatusNotFound) - this means that the user ID that you tried to search for does not yet exist in the table.GetUserResponse struct which contains the user ID, email, and name of the user that was queried. The JSON function is used to conveniently return this Go struct in the form of an HTTP response without having to do explicit JSON marshaling or decoding.The getAllUsers HTTP handler is used to retrieve all rows in the users table.
Add the below code to handler.go file:
getAllUsers function accepts a gin.Context object.Query is used to execute the SELECT * FROM users; query on the database.Scan to copy the columns from the matched query result.GetUserResponse object and add that to a slice.GetUserResponse structs in the form of an HTTP response without having to do explicit JSON marshaling or decoding.UseridThe updateUser HTTP handler is used to update the user name given its id.
Add the below code to handler.go file:
Add the below code to model.go file:
getAllUsers function accepts a gin.Context object.UpdateRequest represents the payload that contains information about the user to be updated (UserID and NewName).ShouldBind parses the request body as JSON (because you will use the application/json Content-Type header). It decodes the JSON payload into the UpdateRequest struct specified as a pointer.Exec is used to execute the update query (UPDATE users SET Name = ? WHERE Userid = ?; query on the database with the new user name and user ID, which were retrieved from the HTTP payload body.RowsAffected on the sql.Result object to confirm that one row has been affected.UseridThe deleteUserWithID HTTP handler is used to update the user name given its id.
Add the below code to handler.go file:
deleteUserWithID function accepts a gin.Context object.Param function.Exec is used to execute the delete query (DELETE FROM users WHERE Userid = ?; query on the database with the user ID that was retrieved earlier.RowsAffected on the sql.Result object to confirm that one row has been affected.The dropAndCreateTable function deletes the users table and re-creates it.
Add the below code to main.go file:
Update the init function to invoke the function (add to the end of the init function):
Exec is used to execute the DROP TABLE query on the database, followed by the CREATE TABLE query.
The HTTP handlers you added earlier (in handler.go file) need to be configured as routes.
Add the below code to the main function (which was earlier empty) in the main.go file:
Also, add the Gin package to the imports section - " github.com/gin-gonic/gin".
Now you are ready to run the program and test the API.
Fetch the Go module dependencies for the program:
You should see output similar to this:
To run the program:
You should see output logs similar to this:
Note: Don't worry about the log message could not drop table - Error 1051: Unknown table' defaultdb.users. This happens only when you run the program for the first time. If you re-run the program again, this will not occur because the users table will already exist in the Vultr MySQL Managed Database instance.
You can now use the HTTP endpoints to test the API's create, read, update and delete functionality.
To create a user (with username user1 and email address user1@foo.com), run the below command in a terminal:
You should get back an HTTP response similar to this:
To create a user (with username user2 and email address user2@foo.com), run the below command in a terminal:
You should get back an HTTP response similar to this:
Notice that the Location HTTP header contains the auto-generated User ID by MySQL.
To get details for the user with ID 1, run the below command in a terminal:
You should get back an HTTP response similar to this:
To get details for the user with ID 2, run the below command in a terminal:
You should get back an HTTP response similar to this:
You get the user information payload in JSON form, along with the HTTP response metadata.
To get details for the user with ID 42, run the below command in a terminal:
You should get back an HTTP response similar to this:
As expected, you got an HTTP 404 because the user with ID 42 does not exist in the database yet.
To get all rows in the users table, run the below command in a terminal:
You should get back an HTTP response similar to this:
You get the array of users in JSON form, along with the HTTP response metadata.
To update the name for the user with ID 1, run the below command in a terminal:
You should get back an HTTP response similar to this:
To verify that the user name was updated, fetch the details for the user with ID 1. Run the below command in a terminal:
You should get back an HTTP response similar to this:
You get the user information payload in JSON form (notice the update name user1_new), along with the HTTP response metadata.
To update the name for the user with ID 42, run the below command in a terminal:
You should get back an HTTP response similar to this:
As expected, you got an HTTP 404 because the user with ID 42 does not exist in the database yet.
To delete a user with ID 1, run the below command in a terminal:
You should get back an HTTP response similar to this:
Verify the contents of the users table and confirm that the deleted user does not exist. Run the below command in a terminal:
You should get back an HTTP response similar to this:
As expected, you only see user2 in the response payload because user1 was just deleted.
To get details for the user with ID 1, run the below command in a terminal:
You should get back an HTTP response similar to this:
As expected, you got an HTTP 404 because the user with ID 1 does not exist in the database yet (it was just deleted).
In this article, you created a Vultr Managed Database for MySQL and used the MySQL Go client library to connect to it securely over TLS. Then you used Gin (a Go web framework) to build an application to expose data in MySQL table with a REST API.
To learn more about Vultr Managed Databases, you can refer to the following documentation:
0 Comments
Be the first to comment and share your perspective with the community.