feat(swagger): implement SendError for BaseAPI handler

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2020-01-19 00:46:11 +00:00
parent 2ea41ca78a
commit 5daa3f4fb3
4 changed files with 97 additions and 11 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
) )
@ -155,3 +156,19 @@ func IsErr(err error, code string) bool {
func IsConflictErr(err error) bool { func IsConflictErr(err error) bool {
return IsErr(err, ConflictCode) return IsErr(err, ConflictCode)
} }
// ErrCode returns code of err
func ErrCode(err error) string {
if err == nil {
return ""
}
var e *Error
if ok := errors.As(err, &e); ok && e.Code != "" {
return e.Code
} else if ok && e.Cause != nil {
return ErrCode(e.Cause)
}
return GeneralCode
}

View File

@ -0,0 +1,43 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package error
import (
"errors"
"testing"
)
func TestErrCode(t *testing.T) {
type args struct {
err error
}
tests := []struct {
name string
args args
want string
}{
{"nil", args{nil}, ""},
{"general err", args{errors.New("general err")}, GeneralCode},
{"code in err", args{&Error{Code: "code in err"}}, "code in err"},
{"code in cause", args{&Error{Cause: &Error{Code: "code in cause"}}}, "code in cause"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ErrCode(tt.args.err); got != tt.want {
t.Errorf("ErrCode() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -16,8 +16,11 @@ package error
import ( import (
"errors" "errors"
ierror "github.com/goharbor/harbor/src/internal/error"
"net/http" "net/http"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
ierror "github.com/goharbor/harbor/src/internal/error"
) )
var ( var (
@ -34,14 +37,7 @@ var (
// APIError generates the HTTP status code and error payload based on the input err // APIError generates the HTTP status code and error payload based on the input err
func APIError(err error) (int, string) { func APIError(err error) (int, string) {
var e *ierror.Error return getHTTPStatusCode(ierror.ErrCode(err)), ierror.NewErrs(err).Error()
statusCode := 0
if errors.As(err, &e) {
statusCode = getHTTPStatusCode(e.Code)
} else {
statusCode = http.StatusInternalServerError
}
return statusCode, ierror.NewErrs(err).Error()
} }
func getHTTPStatusCode(errCode string) int { func getHTTPStatusCode(errCode string) int {
@ -51,3 +47,33 @@ func getHTTPStatusCode(errCode string) int {
} }
return statusCode return statusCode
} }
var _ middleware.Responder = &ErrResponder{}
// ErrResponder error responder
type ErrResponder struct {
err error
}
// WriteResponse ...
func (r *ErrResponder) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
code := ierror.ErrCode(r.err)
rw.WriteHeader(getHTTPStatusCode(code))
var e *ierror.Error
if !errors.As(r.err, &e) {
e = &ierror.Error{
Code: code,
Message: r.err.Error(),
}
}
if err := producer.Produce(rw, e); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
// NewErrResponder returns responder for err
func NewErrResponder(err error) *ErrResponder {
return &ErrResponder{err: err}
}

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"github.com/go-openapi/runtime/middleware" "github.com/go-openapi/runtime/middleware"
errs "github.com/goharbor/harbor/src/server/error"
) )
// BaseAPI base API handler // BaseAPI base API handler
@ -30,6 +31,5 @@ func (*BaseAPI) Prepare(ctx context.Context, operation string, params interface{
// SendError returns response for the err // SendError returns response for the err
func (*BaseAPI) SendError(ctx context.Context, err error) middleware.Responder { func (*BaseAPI) SendError(ctx context.Context, err error) middleware.Responder {
// TODO: implement send error return errs.NewErrResponder(err)
return nil
} }