Handling Errors in Golang

I'm a software developer and computer scientist who loves building things.
Search for a command to run...

I'm a software developer and computer scientist who loves building things.
No comments yet. Be the first to comment.
The Interface Segregation Principle is the I in SOLID design principles. It states that types should not implement methods unrelated to their operations. In essence, interfaces should be designed so that the implementing types are not forced to imple...

The project management iron triangle applied to software development
If you already know how to use a programming language, when learning a new language it is only natural to attempt to draw comparisons. This post is the first in a series, we'll attempt to learn Golang by re-implementing Events APIs in Go. What are th...

This post is inspired by this wonderful post by Evelyn Stender. This post does not explain what a generator is or basic usage, Evelyn's post does a good job of that. Instead, in this post, we will demonstrate how generators can be useful for streamin...

Errors in golang are vastly different from errors in JavaScript. In this post, we will implement error handling for the events project we started building in the first post . That means, handling errors within the module itself as well as errors from event listeners.
First thing of note, with errors in golang is that errors are values not events. In JavaScript, errors (or Exceptions) are things that happen (events) that you need to catch and react to. In golang, errors are returned and you use them as values to make decisions. See this tutorial for more details on error handling.
For the problem we are trying to solve ( see first post, we will have to implement a special error event with a single listener that will print out the error and exit the application; this listener will get overwritten if the user creates a listener for errors.
func (ee EventEmitter) emit(event string, args ...interface{}) {
if event == "error" {
if _, ok := ee.events[event]; ok == false {
fmt.Println(args...)
panic("no listener registered")
}
}
if e, ok := ee.events[event]; ok {
for _, listener := range e.listeners {
_, err := listener(args)
if err != nil {
ee.emit("error", err)
}
}
}
}
We have updated the emit method to cater for when the error event is emitted without a listener being registered. We have also modified the signature for listeners; included return types and allow listeners to take any types (not just strings as before). This means we can check for when listeners return errors and emit the error event.
First thing is to implement a listener for error events, this is because we don't want the application to exit whenever an error is returned from a listener.
var errorHandler = func(args ...interface{}) (interface{}, error) {
errors := args[0].([]interface{})
for _, error := range errors {
fmt.Println("ERROR!", error)
}
return nil, nil
}
This listener needs to be registered within the server initialization method
func (server server) init() {
// Register all listeners
server.eventsEmitter.on("connect", handleConnection)
server.eventsEmitter.on("connect", logMessage)
server.eventsEmitter.on("data", logMessage)
server.eventsEmitter.on("error", errorHandler)
server.eventsEmitter.on("disconnect", handleDisonnection)
}
Next, to trigger the error event, we modify the handleDisconnection listener to always return an error, this will help us test the error event.
var handleDisonnection = func(args ...interface{}) (interface{}, error) {
return nil, errors.New("failed to disconnect")
}
When you run this program, all the listeners are triggered as before. But, this time instead of the message for disconnection we get the message for error in disconnection
http/connection/string Connected successfully
2021/12/29 15:10:40 Connected successfully
2021/12/29 15:10:40 Message from user 1
2021/12/29 15:10:40 Message from user 2
2021/12/29 15:10:40 Message from user 3
2021/12/29 15:10:40 Message from user 4
ERROR! failed to disconnect
Note that we have modified all listeners to follow the new signatures
We still have some unresolved issues with this library, I'll be updating the Github project with improvements as I think of them.