Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error Handling Approaches Discussion #188

Open
ivanspasov99 opened this issue Jul 19, 2023 · 0 comments
Open

Error Handling Approaches Discussion #188

ivanspasov99 opened this issue Jul 19, 2023 · 0 comments

Comments

@ivanspasov99
Copy link

ivanspasov99 commented Jul 19, 2023

Hello,

I am researching different scenarios for propagating errors through Golang API, also different way of encapsulating the errors for the whole API. I will give some examples and I hope to have productive discussion for different approaches with different suggestions. I am familiar with your guide when to use errors but the there is more broader problem about error handling through app.

HTTP Call:

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // business logic

    // Call the API from the Service and get processed object from the dependency and error.
    apiCallProcessedObjet, err := h.service.CallAPI() // internally makes http call

    // could return err
}

Question: How to propagate the status code? We can encapsulate in custom error and propagate it. In this case we should explicitly assert here or in some middleware? If it is in middleware where we should define the error in? In the dependency package or in some APIErrors package which would be shared across whole application? I would be very happy to hear some ideas how you would do it and why :)

Manage your API Errors:
How do you manage your API errors, where do you put them, for example do you use APIErrors package and put every custom error there or you define them directly in the packages where they could arise (that could make direct dependency). I had found some examples in the google cloud
How do you handle them, where and why? What is (not) working for you and why?

I have read a lot of information through the internet but there is almost nothing valuable except telling you what kind of errors Go support and how to use them. I hope you can share some of your experience of handling errors of more complex APIs or give reference where I can read something more meaningful.

I can give something which I see as maybe the best practice as all of the important error through the application are handled in middleware. Something like this

My Guide For Application Layer Errors
Define a handler function

func DocsHandler(writer http.ResponseWriter, request *http.Request) error {
	// business logic with api calls and errors
	return nil
}

Define input type for the error handler which is custom function type

You can mock the function in the tests easily

// Use this special type for your error handler
// you can mock easily
type HTTPTypeHandler func(w http.ResponseWriter, r *http.Request) error

// Pattern for endpoint on middleware chain
func DocsErrorHandler(h HTTPTypeHandler) http.HandlerFunc {
	// return handler function so it can be used in http.HandleFunc
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Execute the final handler, and deal with errors
		err := h(w, r)
		if err != nil {
			// Deal with error here
                         // you can assert different error and have specific logic
		}
	})
}

Guide for package level errors
When you are required to define runtime error which is simple the uber guide greatly define what to use and how to use it.

I prefer using always error initialised like that parsingError := new Error("blabal") so I can validate that the test returns exactly it as I saw in multiple project that people are doing string comparison in the end. You can validate it with errors.Is, errors.As... Exported errors are the same, they are good for reacting in other packages but implies coupling with is the following topic.

Package Coupling
If you have exported error in package and you have reacted upon in on another package you have couple them implicitly. How do you manage that and do you have opinion of moving maybe this errors in errors package or something shared, or you prefer leaving it and make the coupling between the packages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant