DEV Community

Cover image for New golang package to reduce code duplication in APIs
Alexis Viscogliosi
Alexis Viscogliosi

Posted on

New golang package to reduce code duplication in APIs

Hi Golang developers!

I just released a new package that will help you develop APIs in go.

Look at this code :

func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    userID := vars["userID"]

    requestBody, err := ioutil.ReadAll(r.Body)
    if err != nil {
        errorResponse(w, http.StatusInternalServerError, "", err) // <-- your custom error logic that you write for 
                                                                  //      each project
        return
    }

    var requestData ChangePasswordRequest
    if err := json.Unmarshal(requestBody, &requestData); err != nil {
        errorResponse(w, http.StatusInternalServerError, "", err)
        return
    }

    if err = requestData.IsValid(); err != nil {
        errorResponse(w, http.StatusBadRequest, err.Error(), err)
        return
    }

    if err = a.app().ChangePassword(userID, requestData.OldPassword, requestData.NewPassword); err != nil {
        errorResponse(w, http.StatusBadRequest, err.Error(), err)
        return
    }

    jsonStringResponse(w, http.StatusOK, "{}") // <-- your custom code that your are write for each project
}
Enter fullscreen mode Exit fullscreen mode

This is often the code I see on Go projects. There is nothing wrong with writing this because it is very efficient and declarative.

But sometimes we would still like to focus a little more on what matters: business logic.

The version with KCD of this code now:

type ChangePasswordRequest struct {
    UserID string `path:"userID"`
    // ...
}

func (c *ChangePasswordRequest) Validate() error {
    // ...
}

func (a *API) handleChangePassword(request *ChangePasswordRequest) error {
    if err = a.app().ChangePassword(request.UserID, request.OldPassword, request.NewPassword); err != nil {
        return errors.Wrap(err, "unable to change password").WithKind(errors.KindInvalidArgument)
    }

    return nil
}
Enter fullscreen mode Exit fullscreen mode

As you can see the code is more concise and has less boilerplate, it is not more efficient because kcd uses reflection to achieve this simplicity.

If you want to play with this new toy this is the link of the package https://github.com/alexisvisco/kcd

Top comments (0)