In Chapter-7 of our Golang Tutorial, we touched upon ‘Error Handling’ in Golang. In this chapter, let’s explore ‘Common Utilities in Golang Project’.
Properties File Scanner
Golang is having a supportive library for reading and writing properties files. It supports reading the key values from multiple properties file and in Spring style manner like ${key} to the corresponding value.
Value expressions refer to other keys like in ${key}.
We can decode the properties into struct, maps, arrays & values through struct tags.
It is like a java properties scanner for go.
For more info refer https://github.com/magiconair/properties
Package properties provide functions for reading and writing ISO-8859-1 and UTF-8 encoded .properties files and have support for recursive property expansion.
Related read: Learn How To Add Expansion Files In Android?
Java properties files are ISO-8859-1 encoded and use Unicode literals for characters outside the ISO character set. Unicode literals can be used in UTF-8 encoded properties files but aren’t necessary.
Just download this dependency, import its packages, create properties file in key, value format, and use the functions for accessing values of keys.
To load a single properties file, we must have to use –
p:=Properties.MustLoadFile(filename,properties.UTF8)
To load multiple properties files use MustLoadFiles() which loads the files in the given order and merges the result. Missing properties files can be ignored if the ‘ignoreMissing‘ flag is set to true.
Filenames can contain environment variables which are expanded before loading.
Type below on your command prompt for downloading dependency –
>go get -u github.com/magiconair/properties
I have created two properties file exception.properties and message.properties file in my project location
golangdemo/src/mindbowser/config/exception.properties golangdemo/src/mindbowser/config/message.properties
All of the different key/value delimiters ‘ ‘, ‘:’ and ‘=’ are supported as well as the comment characters ‘!’ and ‘#’ and multi-line values.
! this is a comment # and so is this
# the following expressions are equal
Now to load the properties file from the location you need to import the package
import “github.com/magiconair/properties”
Now load the multiple properties like this –
var PropertyFile= []string{"${HOME}/golangdemo/src/mindbowser/config/exception.properties", "${HOME}/golangdemo/src/mindbowser/config/message.properties"} var P, _ = properties.LoadFiles(PropertyFile, properties.UTF8, true)
This will load all the properties from your location specified and store into P reference variable.
Now access the values based on keys using –
P.MustGet(“<Name of Key>”)
OR
P.Get(“<Name of Key>”) /* If key not found it will return panic error*/
Here, we will see the standard approach followed in projects like the actual use of properties file.
Now, see how to deal with properties files –
Here, I’ve created a standard directory structure :
I’ve created two properties files as shown below –
Now I’ve created constants file and mapped the messages and these messages are keys of properties file that we are going to read.
DemoConstants.go package constants var ( LOGIN_SUCCESS = "message.login.success" LOGOUT_SUCCESS = "message.logout.success" LOGOUT_FAILED = "message.logout.failed" USER_NOT_EXIST = "user.not.exist" SERVER_NOT_RESPONDING = "server.not.responding" SERVER_ERROR = "internal.problem" NOT_FOUND = "not.found" EXCEPTION_DAO_USER = "exception.user.dao" )
Now here I’ve created ResourceManager struct that is scanning properties file and by using function it will read the associated value of its key.
ResourceManager.go
package utils import ( "github.com/magiconair/properties" ) var PropertyFiles = []string{"${GOPATH}/src/PropertiesScanner/resources/exception.properties", "${GOPATH}/src/PropertiesScanner/resources/message.properties"} var Props, _ = properties.LoadFiles(PropertyFiles, properties.UTF8, true) type ResourceManager struct { } func (res ResourceManager) GetProperty(propertyName string) string { message := "" var ok bool message, ok = Props.Get(propertyName) if !ok { return Props.MustGet("not.found") } else { return message } }
In above code, as given, I’ve imported github.com/magiconair/properties dependency and loaded the properties file. Here, GetProperty(string) function will accept the string value and again using Get( ) it will read.
main.go package main import ( "PropertiesScanner/utils" "PropertiesScanner/constants" "fmt" ) func main() { //Reading values from properties file /*Here I have created ResourceManager struct like we are using in java to read the properties file. So I've mapped the constants with the messages from properties file. It is a standard approach to read the values from properties file */ resourceManager:=utils.ResourceManager{}; successMsg:=resourceManager.GetProperty(constants.LOGIN_SUCCESS) notFoundMsg:=resourceManager.GetProperty(constants.NOT_FOUND) fmt.Println(successMsg) fmt.Println(notFoundMsg) }
So your output would be –
We can deal with the properties file in many no. of ways, to read more about this properties file scanner library package, visit this link https://github.com/magiconair/properties
Go has support for logging which is implemented in “log” package. It defines a type, Logger, with methods for formatting output. It also has a predefined ‘standard‘ Logger accessible through functions Printf/Println, Fatalf/Fatalln, and Panicf/Panicln, which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message.
For more info about this log package visit: https://golang.org/pkg/log/
But I have used other libraries implemented by some other developers. So we will look into this logger. Basically logger is used to log the application-specific messages. We use loggers to write the log messages to file so in case if an application gets some error we can check the log messages into the log file.
So here I’ve used https://github.com/sirupsen/logrus logger which is really having an efficient implementation of a logger and providing complete compatibility like a logger.
For this, we have to import the below dependency github.com/sirupsen/logrus. This API has provided complete functionality like log4j logger in java.
Again I’ve imported gopkg.in/natefinch/lumberjack.v2 dependency that will create and maintain like –
&lumberjack.Logger{ Filename: "./LogDemo.log", MaxSize: 1, // megabytes after which new file is created MaxBackups: 3, // number of backups MaxAge: 28, //days }
The maximum file size will be 1MB and when the file exceeds this limit then it will create a new log file. MaxBackups field tells that it will keep maximum 3 backup files and MaxAge tells that this file will remain in system for 28 days. Like this, I have created the configuration but you can change it depending on your requirements.
main.go package main import( log "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2" "os" ) func init() { //log.SetFormatter(&log.TextFormatter{}) log.SetFormatter(&log.JSONFormatter{}) //Choose any format //log.SetOutput(os.Stdout) file, err := os.OpenFile("LogDemo.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err == nil { log.SetOutput( &lumberjack.Logger{ Filename: "./LogDemo.log", MaxSize: 1, // megabytes after which new file //created MaxBackups: 3, // number of backups MaxAge: 28, //days }) log.Println(file.Name(),"is generated log file") } else { log.Info("Failed to log to file, using default stderr") } } func main(){ log.Info("Main Function Started") SaveUser() //Calling SaveUser() } func SaveUser(){ //log messages by specifying log level log.Info("SaveUser Success") //to specify info messages log.Error("Error while saving user") //to specify error messages log.Debug("Debug") log.Warn("Warning") }
The log file will be created like this –
The getter setter is the functionality of OOPs i.e. Encapsulation. In java, we can create the getter setter methods to set and get the values of fields. Like java, we also can create the getter and setters in Go and can provide data hiding (if you wish to). Normally in Eclipse IDE (the most preferred IDE by java professionals), we can generate getter setters by choosing option “Generate getter setter” but here in Go we have to create getter/setter manually.
UserModel.go package model type UserModel struct { userName string email string password string } func (user *UserModel) SetuserName(userName string) { user.userName = userName } func (user *UserModel) GetuserName() string { return user.userName } func (user *UserModel) Setemail(email string) { user.email = email } func (user UserModel) Getemail() string { return user.email } func (user *UserModel) Setpassword(password string) { user.password = password } func (user UserModel) GetPassword() string { return user.password }
main.go package main import ( "GetterSetter/model" "fmt" ) func main(){ //Create object of struct UserModel user:=model.UserModel{} user.SetuserName("John Martin") user.GetuserName() user.Setemail("john_martin@gmail.com") user.Getemail() user.Setpassword("johnMartin234") user.GetPassword() fmt.Println(user) }
The O/p will be as expected –
Related read: Optimizing Serverless With Apigee API: An Inside Look At Our Case Study
Copy value from one struct to another struct and more
Sometimes in the project, there could be the need for copying one struct/slice to another. So if we try to do it manually we need to put more efforts. So there is one library that is providing this feature.
So to do this kind of work, we need to import github.com/jinzhu/copier dependency.
main.go package main import ( "fmt" "github.com/jinzhu/copier" ) type User struct { Name string Age int32 } type Employee struct { Name string Age int32 DoubleAge int32 EmployeId int64 } func main() { var ( user = User{Name: "John", Age: 18} users = []User{{Name: "Martin", Age: 18}, {Name: "Ricky", Age: 30}} employee = Employee{} employees = []Employee{} ) //Copy field to field copier.Copy(&employee, &user) fmt.Println(employee) // Copy struct to slice copier.Copy(&employees, &user) fmt.Println(employees) // Copy slice to slice employees = []Employee{} copier.Copy(&employees, &users) fmt.Println(employees) }
The output will be like this. Non-matched fields will be ignored.
To know more about this, visit – https://github.com/jinzhu/copier
How to Effectively Hire and Manage a Remote Team of Developers.
Download NowThe Mindbowser team's professionalism consistently impressed me. Their commitment to quality shone through in every aspect of the project. They truly went the extra mile, ensuring they understood our needs perfectly and were always willing to invest the time to...
CTO, New Day Therapeutics
I collaborated with Mindbowser for several years on a complex SaaS platform project. They took over a partially completed project and successfully transformed it into a fully functional and robust platform. Throughout the entire process, the quality of their work...
President, E.B. Carlson
Mindbowser and team are professional, talented and very responsive. They got us through a challenging situation with our IOT product successfully. They will be our go to dev team going forward.
Founder, Cascada
Amazing team to work with. Very responsive and very skilled in both front and backend engineering. Looking forward to our next project together.
Co-Founder, Emerge
The team is great to work with. Very professional, on task, and efficient.
Founder, PeriopMD
I can not express enough how pleased we are with the whole team. From the first call and meeting, they took our vision and ran with it. Communication was easy and everyone was flexible to our schedule. I’m excited to...
Founder, Seeke
Mindbowser has truly been foundational in my journey from concept to design and onto that final launch phase.
CEO, KickSnap
We had very close go live timeline and Mindbowser team got us live a month before.
CEO, BuyNow WorldWide
If you want a team of great developers, I recommend them for the next project.
Founder, Teach Reach
Mindbowser built both iOS and Android apps for Mindworks, that have stood the test of time. 5 years later they still function quite beautifully. Their team always met their objectives and I'm very happy with the end result. Thank you!
Founder, Mindworks
Mindbowser has delivered a much better quality product than our previous tech vendors. Our product is stable and passed Well Architected Framework Review from AWS.
CEO, PurpleAnt
I am happy to share that we got USD 10k in cloud credits courtesy of our friends at Mindbowser. Thank you Pravin and Ayush, this means a lot to us.
CTO, Shortlist
Mindbowser is one of the reasons that our app is successful. These guys have been a great team.
Founder & CEO, MangoMirror
Kudos for all your hard work and diligence on the Telehealth platform project. You made it possible.
CEO, ThriveHealth
Mindbowser helped us build an awesome iOS app to bring balance to people’s lives.
CEO, SMILINGMIND
They were a very responsive team! Extremely easy to communicate and work with!
Founder & CEO, TotTech
We’ve had very little-to-no hiccups at all—it’s been a really pleasurable experience.
Co-Founder, TEAM8s
Mindbowser was very helpful with explaining the development process and started quickly on the project.
Executive Director of Product Development, Innovation Lab
The greatest benefit we got from Mindbowser is the expertise. Their team has developed apps in all different industries with all types of social proofs.
Co-Founder, Vesica
Mindbowser is professional, efficient and thorough.
Consultant, XPRIZE
Very committed, they create beautiful apps and are very benevolent. They have brilliant Ideas.
Founder, S.T.A.R.S of Wellness
Mindbowser was great; they listened to us a lot and helped us hone in on the actual idea of the app. They had put together fantastic wireframes for us.
Co-Founder, Flat Earth
Ayush was responsive and paired me with the best team member possible, to complete my complex vision and project. Could not be happier.
Founder, Child Life On Call
The team from Mindbowser stayed on task, asked the right questions, and completed the required tasks in a timely fashion! Strong work team!
CEO, SDOH2Health LLC
Mindbowser was easy to work with and hit the ground running, immediately feeling like part of our team.
CEO, Stealth Startup
Mindbowser was an excellent partner in developing my fitness app. They were patient, attentive, & understood my business needs. The end product exceeded my expectations. Thrilled to share it globally.
Owner, Phalanx
Mindbowser's expertise in tech, process & mobile development made them our choice for our app. The team was dedicated to the process & delivered high-quality features on time. They also gave valuable industry advice. Highly recommend them for app development...
Co-Founder, Fox&Fork