mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Improvements on API error, swagger and status code (#428)
* improvements on API error, swagger and status code * missing validation * removing typo * fix if-within-if * fix handle app delete
This commit is contained in:
@@ -36,24 +36,28 @@ func (s *Server) handleAppCreate(c *gin.Context) {
|
||||
|
||||
err = s.FireBeforeAppCreate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
return
|
||||
}
|
||||
|
||||
app, err := s.Datastore.InsertApp(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
if err == models.ErrAppsAlreadyExists {
|
||||
log.WithError(err).Debug(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusConflict, simpleError(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
err = s.FireAfterAppCreate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, appResponse{"App successfully created", app})
|
||||
c.JSON(http.StatusOK, appResponse{"App successfully created", app})
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ func (s *Server) handleAppDelete(c *gin.Context) {
|
||||
|
||||
routes, err := s.Datastore.GetRoutesByApp(ctx, app.Name, &models.RouteFilter{})
|
||||
if err != nil {
|
||||
log.WithError(err).Debug(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsRemoving))
|
||||
log.WithError(err).Error(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -30,25 +30,26 @@ func (s *Server) handleAppDelete(c *gin.Context) {
|
||||
|
||||
err = s.FireBeforeAppDelete(ctx, app)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.Datastore.RemoveApp(ctx, app.Name); err != nil {
|
||||
err = s.Datastore.RemoveApp(ctx, app.Name)
|
||||
if err == models.ErrAppsNotFound {
|
||||
log.WithError(err).Debug(models.ErrAppsRemoving)
|
||||
if err == models.ErrAppsNotFound {
|
||||
c.JSON(http.StatusNotFound, simpleError(models.ErrAppsNotFound))
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsRemoving))
|
||||
}
|
||||
c.JSON(http.StatusNotFound, simpleError(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
err = s.FireAfterAppDelete(ctx, app)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrAppsRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ func (s *Server) handleAppList(c *gin.Context) {
|
||||
|
||||
apps, err := s.Datastore.GetApps(ctx, filter)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug(models.ErrAppsList)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsList))
|
||||
log.WithError(err).Error(models.ErrAppsList)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestAppCreate(t *testing.T) {
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
|
||||
// success
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusCreated, nil},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusOK, nil},
|
||||
} {
|
||||
rnr, cancel := testRunner(t)
|
||||
router := testRouter(test.mock, &mqs.Mock{}, rnr, tasks)
|
||||
@@ -226,7 +226,7 @@ func TestAppUpdate(t *testing.T) {
|
||||
Apps: []*models.App{{
|
||||
Name: "myapp",
|
||||
}},
|
||||
}, "/v1/apps/myapp", `{ "app": { "name": "othername" } }`, http.StatusForbidden, nil},
|
||||
}, "/v1/apps/myapp", `{ "app": { "name": "othername" } }`, http.StatusBadRequest, nil},
|
||||
} {
|
||||
rnr, cancel := testRunner(t)
|
||||
router := testRouter(test.mock, &mqs.Mock{}, rnr, tasks)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *Server) handleAppUpdate(c *gin.Context) {
|
||||
|
||||
if wapp.App.Name != "" {
|
||||
log.Debug(models.ErrAppsNameImmutable)
|
||||
c.JSON(http.StatusForbidden, simpleError(models.ErrAppsNameImmutable))
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrAppsNameImmutable))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -38,25 +38,28 @@ func (s *Server) handleAppUpdate(c *gin.Context) {
|
||||
|
||||
err = s.FireAfterAppUpdate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
app, err := s.Datastore.UpdateApp(ctx, wapp.App)
|
||||
if err != nil {
|
||||
if err == models.ErrAppsNotFound {
|
||||
log.WithError(err).Debug(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsUpdate))
|
||||
c.JSON(http.StatusNotFound, simpleError(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
err = s.FireAfterAppUpdate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
// Nothing to update right now in apps
|
||||
c.JSON(http.StatusOK, appResponse{"App successfully updated", app})
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@ func (s *Server) handleRouteCreate(c *gin.Context) {
|
||||
|
||||
err := c.BindJSON(&wroute)
|
||||
if err != nil {
|
||||
log.WithError(err).Error(models.ErrInvalidJSON)
|
||||
log.WithError(err).Debug(models.ErrInvalidJSON)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON))
|
||||
return
|
||||
}
|
||||
|
||||
if wroute.Route == nil {
|
||||
log.WithError(err).Error(models.ErrInvalidJSON)
|
||||
log.WithError(err).Debug(models.ErrInvalidJSON)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesMissingNew))
|
||||
return
|
||||
}
|
||||
@@ -32,20 +32,22 @@ func (s *Server) handleRouteCreate(c *gin.Context) {
|
||||
wroute.Route.AppName = ctx.Value("appName").(string)
|
||||
|
||||
if err := wroute.Validate(); err != nil {
|
||||
log.Error(err)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Debug(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusBadRequest, simpleError(err))
|
||||
return
|
||||
}
|
||||
|
||||
if wroute.Route.Image == "" {
|
||||
log.WithError(models.ErrRoutesValidationMissingImage).Debug(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesValidationMissingImage))
|
||||
return
|
||||
}
|
||||
|
||||
err = s.Runner.EnsureImageExists(ctx, &task.Config{
|
||||
Image: wroute.Route.Image,
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrUsableImage))
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrUsableImage))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -65,33 +67,37 @@ func (s *Server) handleRouteCreate(c *gin.Context) {
|
||||
|
||||
err = s.FireBeforeAppCreate(ctx, newapp)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Datastore.InsertApp(ctx, newapp)
|
||||
if err != nil {
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
log.WithError(err).Error(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
err = s.FireAfterAppCreate(ctx, newapp)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
log.WithError(err).Error(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
route, err := s.Datastore.InsertRoute(ctx, wroute.Route)
|
||||
if err != nil {
|
||||
if err == models.ErrRoutesAlreadyExists {
|
||||
log.WithError(err).Debug(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusConflict, simpleError(models.ErrRoutesAlreadyExists))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesCreate))
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, routeResponse{"Route successfully created", route})
|
||||
c.JSON(http.StatusOK, routeResponse{"Route successfully created", route})
|
||||
}
|
||||
|
||||
@@ -17,18 +17,12 @@ func (s *Server) handleRouteDelete(c *gin.Context) {
|
||||
appName := ctx.Value("appName").(string)
|
||||
routePath := path.Clean(ctx.Value("routePath").(string))
|
||||
|
||||
route, err := s.Datastore.GetRoute(ctx, appName, routePath)
|
||||
if err != nil || route == nil {
|
||||
log.Error(models.ErrRoutesNotFound)
|
||||
c.JSON(http.StatusNotFound, simpleError(models.ErrRoutesNotFound))
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.Datastore.RemoveRoute(ctx, appName, routePath); err != nil {
|
||||
log.WithError(err).Debug(models.ErrRoutesRemoving)
|
||||
if err == models.ErrRoutesNotFound {
|
||||
log.WithError(err).Debug(models.ErrRoutesRemoving)
|
||||
c.JSON(http.StatusNotFound, simpleError(models.ErrRoutesNotFound))
|
||||
} else {
|
||||
log.WithError(err).Error(models.ErrRoutesRemoving)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesRemoving))
|
||||
}
|
||||
return
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
"github.com/iron-io/runner/common"
|
||||
@@ -20,16 +19,14 @@ func (s *Server) handleRouteGet(c *gin.Context) {
|
||||
|
||||
route, err := s.Datastore.GetRoute(ctx, appName, routePath)
|
||||
if err != nil && err != models.ErrRoutesNotFound {
|
||||
|
||||
log.WithError(err).Error(models.ErrRoutesGet)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet))
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
} else if route == nil {
|
||||
log.Debug(models.ErrRoutesNotFound)
|
||||
c.JSON(http.StatusNotFound, simpleError(models.ErrRoutesNotFound))
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{"route": route}).Debug("Got route")
|
||||
|
||||
c.JSON(http.StatusOK, routeResponse{"Successfully loaded route", route})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
"github.com/iron-io/runner/common"
|
||||
@@ -28,13 +27,15 @@ func (s *Server) handleRouteList(c *gin.Context) {
|
||||
routes, err = s.Datastore.GetRoutes(ctx, filter)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == models.ErrAppsNotFound {
|
||||
log.WithError(err).Debug(models.ErrRoutesGet)
|
||||
c.JSON(http.StatusNotFound, simpleError(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrRoutesGet)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet))
|
||||
c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{"routes": routes}).Debug("Got routes")
|
||||
|
||||
c.JSON(http.StatusOK, routesResponse{"Sucessfully listed routes", routes})
|
||||
}
|
||||
|
||||
@@ -27,14 +27,14 @@ func TestRouteCreate(t *testing.T) {
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "path": "/myroute" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "path": "/myroute" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello" } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "myroute" } }`, http.StatusInternalServerError, models.ErrRoutesValidationInvalidPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "myroute" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidPath},
|
||||
{&datastore.Mock{}, "/v1/apps/$/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
|
||||
// success
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusCreated, nil},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusOK, nil},
|
||||
} {
|
||||
rnr, cancel := testRunner(t)
|
||||
router := testRouter(test.mock, &mqs.Mock{}, rnr, tasks)
|
||||
@@ -212,7 +212,7 @@ func TestRouteUpdate(t *testing.T) {
|
||||
Path: "/myroute/do",
|
||||
},
|
||||
},
|
||||
}, "/v1/apps/a/routes/myroute/do", `{ "route": { "path": "/otherpath" } }`, http.StatusForbidden, nil},
|
||||
}, "/v1/apps/a/routes/myroute/do", `{ "route": { "path": "/otherpath" } }`, http.StatusBadRequest, nil},
|
||||
} {
|
||||
rnr, cancel := testRunner(t)
|
||||
router := testRouter(test.ds, &mqs.Mock{}, rnr, tasks)
|
||||
|
||||
@@ -25,14 +25,14 @@ func (s *Server) handleRouteUpdate(c *gin.Context) {
|
||||
}
|
||||
|
||||
if wroute.Route == nil {
|
||||
log.WithError(err).Error(models.ErrInvalidJSON)
|
||||
log.Debug(models.ErrRoutesMissingNew)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesMissingNew))
|
||||
return
|
||||
}
|
||||
|
||||
if wroute.Route.Path != "" {
|
||||
log.Debug(models.ErrRoutesPathImmutable)
|
||||
c.JSON(http.StatusForbidden, simpleError(models.ErrRoutesPathImmutable))
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesPathImmutable))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,14 +44,19 @@ func (s *Server) handleRouteUpdate(c *gin.Context) {
|
||||
Image: wroute.Route.Image,
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrUsableImage))
|
||||
log.WithError(err).Debug(models.ErrRoutesUpdate)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrUsableImage))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
route, err := s.Datastore.UpdateRoute(ctx, wroute.Route)
|
||||
if err != nil {
|
||||
if err == models.ErrRoutesNotFound {
|
||||
log.WithError(err).Debug(models.ErrRoutesUpdate)
|
||||
c.JSON(http.StatusNotFound, simpleError(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error(models.ErrRoutesUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesUpdate))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -104,11 +104,11 @@ func TestFullStack(t *testing.T) {
|
||||
body string
|
||||
expectedCode int
|
||||
}{
|
||||
{"create my app", "POST", "/v1/apps", `{ "app": { "name": "myapp" } }`, http.StatusCreated},
|
||||
{"create my app", "POST", "/v1/apps", `{ "app": { "name": "myapp" } }`, http.StatusOK},
|
||||
{"list apps", "GET", "/v1/apps", ``, http.StatusOK},
|
||||
{"get app", "GET", "/v1/apps/myapp", ``, http.StatusOK},
|
||||
{"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "iron/hello" } }`, http.StatusCreated},
|
||||
{"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "iron/error" } }`, http.StatusCreated},
|
||||
{"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "iron/hello" } }`, http.StatusOK},
|
||||
{"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "iron/error" } }`, http.StatusOK},
|
||||
{"get myroute", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusOK},
|
||||
{"get myroute2", "GET", "/v1/apps/myapp/routes/myroute2", ``, http.StatusOK},
|
||||
{"get all routes", "GET", "/v1/apps/myapp/routes", ``, http.StatusOK},
|
||||
|
||||
Reference in New Issue
Block a user