Welcome back to my journey of learning Golang! In this blog post, I'll be sharing my progress and insights from Day 3 of my learning experience. Today, I'm excited to dive into two fundamental aspects of building a web application with Golang: connecting to a database using GORM and implementing the Model-View-Controller (MVC) architectural pattern.
Throughout this post, I'll be taking you through the steps I took to implement these features, as well as the key concepts and best practices I learned along the way. Let's get started!
The Project
For the 3rd project using Golang, I will create a simple API to store and manage books. This project will contain a CRUD function, database connetion to MySQL, and code in different file to implement the MVC architectural.
For testing I use Postman but I will not talk about it here, since I already use that before learning Golang and this blog is about what I learn when builing Golang project.
You can find the source code in my GitHub here.
MVC
The Model-View-Controller (MVC) architectural pattern is a widely used design pattern in software development, and Golang is no exception. I already work on creating a project using a structural folder like MVC but I write about this here, because I just now know there is a term about it, I thought it was just a normal project structure.
MVC separates an application into three interconnected components: the Model, the View, and the Controller. The Model represents the data and business logic of the application, the View is responsible for rendering the user interface (for an API, a json response), and the Controller handles user input and updates the Model and View as necessary.
Below is the file structure that I have created.
So to be short, the config folder will contain the configuration on how to connect with the database. The controllers folder will be have the function that handle the user request, updating the model, and return the result to the user to be viewed. The models folder will contain the object structure of the book, declaring the method that will update or manipulate the data on the model or object. The routes folder will contain the router using gorilla mux, and connecting it to the function on the controller.
The utils folder will contain the utility function that is general can be helpful on multiple file, like parsing data json and convert it to be the model book. The main.go file will have the code to run the server and assign the router on routes folder.
The step to create this MVC structure file maybe vary, because I think its about preference. For me I find it easy with this order
config --> models --> controllers --> routes --> main.go ; as for the utils folder can be changed as needed.
GORM
GORM is an object-relational mapping (ORM) library for Golang that simplifies the process of interacting with databases. It provides a powerful and intuitive interface for managing database connections, executing queries, and mapping database tables to Go structs. With GORM, developers can write database queries using Go code rather than SQL, which can make their code more concise, readable, and easier to maintain. In addition to supporting popular relational databases such as MySQL.
You can find the GitHub repo here.
GORM is the equivalent of Sequelize in Node.js and SQLAlchemy in Python, but for Golang.
The first thing to do ofcourse connecting to the database, which will be started in the book model file, but the configuration and function will be in the config folder. Here is the code to initiate the connection
d, err := gorm.Open("mysql", "username:password@tcp(127.0.0.1:3306)/databasename?charset=utf8&parseTime=True&loc=Local")
as you can see the first part before the question "?" mark, will contain the username, password, port to connect, and the database name, but on the next part like "charset" is mandatory but you can change the value to your preference . Charset can be set to a different character set depending on the database's configuration and the type of data being stored. parseTime can be set to false if you don't want GORM to automatically parse datetime fields. loc can be set to a different time zone depending on your application's requirements.
the 'd' value will contain the representation of the gorm connection, while 'err' is an error object that will be nil if the connection was successful.
You also notice on the first parameter of the function, I use "mysql" since that is my target database. But to be able to use the mysql package in gorm, we will need to get the driver for mysql for gorm. You can get it with this command on terminal.
go get "github.com/jinzhu/gorm/dialects/mysql"
To import this extra package you will need underscore "_" in front of the string package name, I will talk about this more in below section, but basically we just want the effect of that package, not really using it in our code.
With gorm we can also migrate the models we have created to database automatically, just like the below code
The gorm.Model is a base struct of model definition that will include "Id", "CreatedAt", "UpdatedAt", and "DeletedAt". To migrate the model, we can just use the function "AutoMigrate" with the parameter the model that want to be migrated.
To write a queries is pretty easy and self-explanatory to me, below is the example on how to find data in the table using gorm.
var book Book
db := db.Where("ID=?", Id).Find(&book)
// Select * from `Book` where ID=id
The result will be stored in the book variable.
Underscore ( _ ) when importing package
Underscore (_) is used to ignore the values. If you don't want to use specific values while unpacking, just assign that value to underscore (_). For example a function called "divide" will take a number a and b, and return the divided result and the reminder result (modulo).
result, _ = divide(a, b)
We didn't want to use the reminder, but the divide function will still return it, so we will use the underscore (_) to store it.
When importing a package that we didn't want to actually use in the code, but we need the side-effect when importing the package, like triggering the "init" function inside the package, we need to write underscore (_) in front of it when importing.
This code will run the "init" function in mysql package so it will declare a package-level variable that can be used in gorm package.
Conclusion
By learning and using tools such as GORM and the MVC pattern, developers can create efficient, scalable, and maintainable applications that can handle complex data operations and provide a great user experience.
Whether you're a seasoned developer or just getting started with Golang, taking the time to learn these tools and techniques can help you take your skills to the next level and create great software that meets your users' needs.
In this project I also learn something new like init function, the difference between method and function, declaring variable with var and without var in Golang, and more, but I didn't write it all to keep this blog not so long and readable. So go ahead and dive in, explore the possibilities, and see what you can create with Golang.
And that's it for this post! I hope you found it helpful and informative. Be sure to check out my next blog post where I'll be exploring more advanced topics in Golang development. Thanks for reading, and happy coding!