Hiding Error From API

(Jauhar Arifin) #1

How we handle error from the api?

Suppose we create server that expose functionality to getUserById. There are some options to use for exposing our functionality (ex: using grpc/rest/graphql). There are some options to persist out data too (ex: mysql,redis, or just in memory?). Suppose I have interface:

package user

type Service interface {
    UserByID(ID: string): (*User, error)

and then we can implement it using mysql/sqlite/inmemory. But all of this implementation have different behaviour and can return different error. Mysql may return connection error, sqlite may return error that indicates no disk space available.

When user call out API, it might go to graphql -> user.Service -> maybe user.Store?. And when error happened, we want our API to provide error information to the user (ex: by using error code like NoSuchUser, TooManyRequest). But we don’t want user to know internal error like ConnectionError, DiskError etc. We want hide the internal error to InternalServerError to user.

So how our implementation of user.Service should return the error so our api can decide whether to hide that error into InternalServerError.

I found really nice article Don’t just check errors, handle them gracefully by Dave Cheney.
It says that we should assert error by behaviour instead of type.

Should we create interface IsInternalError, so the api can now whether they should hide the error. But how does the implementation of user.Service know that it should returns error that implement this interface?

(George Calianu) #2

Supposing you work on HTTP, you can simply return a JSON containing the error code and some explanations or even a more complex structure. Another simple method is returning a plain text error message and coresponding HTTP status code in header, eg:

http.Error(w, "Session expired", http.StatusNetworkAuthenticationRequired)

(Jauhar Arifin) #3

But, what if we don’t want the implementation of user.Service to depend to the technology we used. Can we create a loosely coupled implementation of user.Service that doesn’t care whether we use HTTP, TCP, etc?

(George Calianu) #4

Yes, you can create your own errors.

(Jauhar Arifin) #5

Yes, actually I thinking the same thing at first. And then I read this article: Don’t just check errors, handle them gracefully. It says that we should assert error by its behaviour instead of its type.