updated jsvm errors handling

This commit is contained in:
Gani Georgiev 2023-07-18 12:33:18 +03:00
parent 0110869c89
commit 71a70bac9d
4 changed files with 65 additions and 22 deletions

View File

@ -2,6 +2,7 @@
package apis package apis
import ( import (
"database/sql"
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
@ -11,7 +12,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/dop251/goja"
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware" "github.com/labstack/echo/v5/middleware"
"github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/core"
@ -59,14 +59,6 @@ func InitApi(app core.App) (*echo.Echo, error) {
return return
} }
// manually extract the goja exception error value for
// consistency when throwing or returning errors
if jsException, ok := err.(*goja.Exception); ok {
if wrapped, ok := jsException.Value().Export().(error); ok {
err = wrapped
}
}
var apiErr *ApiError var apiErr *ApiError
switch v := err.(type) { switch v := err.(type) {
@ -85,8 +77,13 @@ func InitApi(app core.App) (*echo.Echo, error) {
if err != nil && app.IsDebug() { if err != nil && app.IsDebug() {
log.Println(err) log.Println(err)
} }
if err != nil && errors.Is(err, sql.ErrNoRows) {
apiErr = NewNotFoundError("", err)
} else {
apiErr = NewBadRequestError("", err) apiErr = NewBadRequestError("", err)
} }
}
event := new(core.ApiErrorEvent) event := new(core.ApiErrorEvent)
event.HttpContext = c event.HttpContext = c

View File

@ -214,7 +214,6 @@ func TestRemoveTrailingSlashMiddleware(t *testing.T) {
} }
func TestEagerRequestInfoCache(t *testing.T) { func TestEagerRequestInfoCache(t *testing.T) {
scenarios := []tests.ApiScenario{ scenarios := []tests.ApiScenario{
{ {
Name: "custom non-api group route", Name: "custom non-api group route",

View File

@ -77,9 +77,7 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
// check for returned error or false // check for returned error or false
if res != nil { if res != nil {
exported := res.Export() switch v := res.Export().(type) {
if exported != nil {
switch v := exported.(type) {
case error: case error:
return v return v
case bool: case bool:
@ -88,7 +86,6 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
} }
} }
} }
}
return err return err
}) })
@ -156,8 +153,16 @@ func routerBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
e.Router.Add(strings.ToUpper(method), path, func(c echo.Context) error { e.Router.Add(strings.ToUpper(method), path, func(c echo.Context) error {
return executors.run(func(executor *goja.Runtime) error { return executors.run(func(executor *goja.Runtime) error {
executor.Set("__args", []any{c}) executor.Set("__args", []any{c})
_, err := executor.RunProgram(pr) res, err := executor.RunProgram(pr)
executor.Set("__args", goja.Undefined()) executor.Set("__args", goja.Undefined())
// check for returned error
if res != nil {
if v, ok := res.Export().(error); ok {
return v
}
}
return err return err
}) })
}, wrappedMiddlewares...) }, wrappedMiddlewares...)
@ -207,9 +212,17 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]echo.M
return executors.run(func(executor *goja.Runtime) error { return executors.run(func(executor *goja.Runtime) error {
executor.Set("__args", []any{next}) executor.Set("__args", []any{next})
executor.Set("__args2", []any{c}) executor.Set("__args2", []any{c})
_, err := executor.RunProgram(pr) res, err := executor.RunProgram(pr)
executor.Set("__args", goja.Undefined()) executor.Set("__args", goja.Undefined())
executor.Set("__args2", goja.Undefined()) executor.Set("__args2", goja.Undefined())
// check for returned error
if res != nil {
if v, ok := res.Export().(error); ok {
return v
}
}
return err return err
}) })
} }

View File

@ -22,6 +22,7 @@ import (
"github.com/dop251/goja_nodejs/require" "github.com/dop251/goja_nodejs/require"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/labstack/echo/v5"
"github.com/pocketbase/dbx" "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations" m "github.com/pocketbase/pocketbase/migrations"
@ -191,6 +192,11 @@ func (p *plugin) registerHooks() error {
return nil return nil
} }
p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.HTTPErrorHandler = p.normalizeServeExceptions(e.Router.HTTPErrorHandler)
return nil
})
// this is safe to be shared across multiple vms // this is safe to be shared across multiple vms
registry := new(require.Registry) registry := new(require.Registry)
@ -236,6 +242,34 @@ func (p *plugin) registerHooks() error {
return nil return nil
} }
// normalizeExceptions wraps the provided error handler and returns a new one
// with extracted goja exception error value for consistency when throwing or returning errors.
func (p *plugin) normalizeServeExceptions(oldErrorHandler echo.HTTPErrorHandler) echo.HTTPErrorHandler {
return func(c echo.Context, err error) {
defer func() {
oldErrorHandler(c, err)
}()
if err == nil || c.Response().Committed {
return // no error or already committed
}
jsException, ok := err.(*goja.Exception)
if !ok {
return // no exception
}
switch v := jsException.Value().Export().(type) {
case error:
err = v
case map[string]any: // goja.GoError
if vErr, ok := v["value"].(error); ok {
err = vErr
}
}
}
}
// watchHooks initializes a hooks file watcher that will restart the // watchHooks initializes a hooks file watcher that will restart the
// application (*if possible) in case of a change in the hooks directory. // application (*if possible) in case of a change in the hooks directory.
// //