incubator-devlake icon indicating copy to clipboard operation
incubator-devlake copied to clipboard

[Refactor][Plugin API] Dispart devlake's backend error and expections

Open d4x1 opened this issue 2 years ago • 2 comments

What and why to refactor

What are you trying to refactor? Why should it be refactored now?

Recently I sumbit PR #6071 , it's caused by mismatched field's type from plugin zentao's remote API response. Usually, all known errors in the server side can be wrapped to an error message to the client side, only unknown errors/expections can cause server api return http status code 500.

Our current code will return http status code 500 because if plugin returns an error with nil body here https://github.com/apache/incubator-devlake/blob/main/backend/server/api/router.go#L135.

We have an similar issue #6038, and there will be more problems in foreseeable future. and it's a unreasonable design. So refactor is necessary.

Describe the solution you'd like

How to refactor?

  1. Frontend Support api body struct for all plugin related APIs.
type TypedApiBody[T any] struct {
	Success bool     `json:"success"`
	Message string   `json:"message"`
	Causes  []string `json:"causes"`
	Data    T        `json:"data"`
}
  1. Backend
  • In plugins' API, if some errors occur, handle errors like this:
func PluginAPI(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
    err := doSth()
    if err != nil {
        log.Error(err, "some additional info")  // log it, necessary!!!
        return TypedApiBody{
            Success: False,
            Message: "some  useful error message",
            Causes: []string{"reason A", "reason B"}
        }, nil
    }
    return respBody, nil
}
  • In plugin handler's caller, wrap handler then recover it.
callHandler := func(input *ApiResourceInput) (output *ApiResourceOutput,  err errors.Error){
    defer func(){
        if recoverErr := recover(); recoverErr != nil {
            log.Error(err, "some additional info")
            err = recoverErr
        }
    } 
    ouput, err = handler(input)
}
output, err := callHandler(input)
if err != nil {
    if output != nil && output.Body != nil {
	logruslog.Global.Error(err, "")
        	shared.ApiOutputSuccess(c, output.Body, err.GetType().GetHttpCode())
	} else {
		shared.ApiOutputError(c, err)
	}
}

Related issues

#6038 #6071

Additional context

Add any other context or screenshots about the feature request here.

d4x1 avatar Sep 13 '23 03:09 d4x1

This issue has been automatically marked as stale because it has been inactive for 60 days. It will be closed in next 7 days if no further activity occurs.

github-actions[bot] avatar Nov 13 '23 00:11 github-actions[bot]

This issue has been automatically marked as stale because it has been inactive for 60 days. It will be closed in next 7 days if no further activity occurs.

github-actions[bot] avatar Jan 13 '24 00:01 github-actions[bot]

This issue has been automatically marked as stale because it has been inactive for 60 days. It will be closed in next 7 days if no further activity occurs.

github-actions[bot] avatar Mar 14 '24 00:03 github-actions[bot]

This issue has been closed because it has been inactive for a long time. You can reopen it if you encounter the similar problem in the future.

github-actions[bot] avatar Mar 22 '24 00:03 github-actions[bot]