Commit a26d6484 authored by Lukas Matt's avatar Lukas Matt

Optimized API response codes and updated docs

parent b3110c3a
......@@ -21,7 +21,7 @@ import (
"github.com/revel/revel"
"gopkg.in/ganggo/api.v0/app/helpers"
"gopkg.in/ganggo/ganggo.v0/app/models"
"errors"
"net/http"
)
/**
......@@ -52,7 +52,7 @@ type ApiAspect struct {
* @apiSuccess {Boolean} Default Default aspect
* @apiSuccess {Array} Memberships Aspect memberships
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -66,13 +66,20 @@ type ApiAspect struct {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
*/
func (a ApiAspect) ShowPerson() revel.Result {
var (
......@@ -83,14 +90,14 @@ func (a ApiAspect) ShowPerson() revel.Result {
user, err := models.CurrentUser(a.Params, a.Session)
if err != nil {
revel.AppLog.Error("Failed to get current user :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return a.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
err = aspects.FindByUserPersonID(user.ID, personID)
if err != nil {
revel.AppLog.Error("Failed to find user by person id :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return a.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
return a.RenderJSON(aspects)
......@@ -111,7 +118,7 @@ func (a ApiAspect) ShowPerson() revel.Result {
* @apiSuccess {Number} AspectID Aspect database ID
* @apiSuccess {Number} PersonID Person database ID
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -123,13 +130,14 @@ func (a ApiAspect) ShowPerson() revel.Result {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
*/
func (a ApiAspect) CreatePerson() revel.Result {
var personID, aspectID uint
......@@ -144,8 +152,8 @@ func (a ApiAspect) CreatePerson() revel.Result {
err := membership.Create()
if err != nil {
revel.AppLog.Error("Failed to create membership :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return a.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
return a.RenderJSON(membership)
......@@ -166,7 +174,7 @@ func (a ApiAspect) CreatePerson() revel.Result {
* @apiSuccess {Number} AspectID Aspect database ID
* @apiSuccess {Number} PersonID Person database ID
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -178,13 +186,14 @@ func (a ApiAspect) CreatePerson() revel.Result {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
*/
func (a ApiAspect) DeletePerson() revel.Result {
var personID, aspectID uint
......@@ -199,8 +208,8 @@ func (a ApiAspect) DeletePerson() revel.Result {
err := membership.Delete()
if err != nil {
revel.AppLog.Error("Failed to delete membership :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return a.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
return a.RenderJSON(membership)
......@@ -209,8 +218,8 @@ func (a ApiAspect) DeletePerson() revel.Result {
func (a ApiAspect) Index(fields string) revel.Result {
user, err := models.CurrentUser(a.Params, a.Session)
if err != nil {
revel.AppLog.Error("Failed to get current user :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return a.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
return a.RenderJSON(
......@@ -234,7 +243,7 @@ func (a ApiAspect) Index(fields string) revel.Result {
* @apiSuccess {Boolean} Default Default aspect
* @apiSuccess {Array} Memberships Aspect memberships
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {
* "ID": 1,
......@@ -246,26 +255,38 @@ func (a ApiAspect) Index(fields string) revel.Result {
* "Memberships": [...]
* }
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 Bad Request
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (a ApiAspect) Create() revel.Result {
name := a.Params.Get("aspect_name")
if name == "" {
errMsg := "Aspect name seams to be empty"
revel.AppLog.Error(errMsg)
return a.RenderApiError(errors.New(errMsg))
if helpers.EmptyString(name) {
a.Log.Error(TAG, "api", ERR_EMPTY_STRING)
return a.ApiError(http.StatusBadRequest, ERR_EMPTY_STRING)
}
user, err := models.CurrentUser(a.Params, a.Session)
if err != nil {
revel.AppLog.Error("Failed to get current user :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return a.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
aspect := models.Aspect{
......@@ -275,8 +296,8 @@ func (a ApiAspect) Create() revel.Result {
err = aspect.Create()
if err != nil {
revel.AppLog.Error("Failed creating an aspect :%s", err.Error())
return a.RenderApiError(err)
a.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return a.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
return a.RenderJSON(aspect)
......
......@@ -20,7 +20,18 @@ package controllers
import (
"net/http"
"github.com/revel/revel"
"errors"
)
const (
TAG = "APILogger"
// error messages
ERR_EMPTY_STRING = "String is empty"
ERR_GRANT_TYPE = "Grant type not supported"
ERR_PASSWORD = "Password did not match"
ERR_UNAUTHORIZED = "You are not authenticated"
ERR_SERVER = "Internal server error"
ERR_NOT_FOUND = "Not found"
ERR_NOT_IMPLEMENTED = "Not implemented"
)
type ApiHelper struct {
......@@ -32,11 +43,10 @@ type ApiError struct {
}
func (c ApiHelper) CatchAll() revel.Result {
c.Response.Status = http.StatusNotImplemented
return c.RenderApiError(errors.New("Not implemented"))
return c.ApiError(http.StatusNotImplemented, ERR_NOT_IMPLEMENTED)
}
func (c ApiHelper) RenderApiError(err error) revel.Result {
c.Response.Status = http.StatusBadRequest
return c.RenderJSON(ApiError{err.Error()})
func (c ApiHelper) ApiError(status int, msg string) revel.Result {
c.Response.Status = status
return c.RenderJSON(ApiError{msg})
}
......@@ -21,7 +21,9 @@ import (
"github.com/revel/revel"
"gopkg.in/ganggo/ganggo.v0/app/models"
"gopkg.in/ganggo/ganggo.v0/app/jobs"
"gopkg.in/ganggo/api.v0/app/helpers"
federation "gopkg.in/ganggo/federation.v0"
"net/http"
)
/**
......@@ -54,7 +56,7 @@ type ApiComment struct {
* @apiSuccess {Hash} CommentSignature Signature
* @apiSuccess {Hash} Person Person structure
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -71,13 +73,14 @@ type ApiComment struct {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
*/
func (c ApiComment) Index() revel.Result {
var (
......@@ -88,8 +91,8 @@ func (c ApiComment) Index() revel.Result {
c.Params.Bind(&postID, "id")
err := comments.FindByPostID(postID)
if err != nil {
revel.AppLog.Error(err.Error())
return c.RenderApiError(err)
c.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return c.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
return c.RenderJSON(comments)
}
......@@ -104,13 +107,26 @@ func (c ApiComment) Index() revel.Result {
* @apiParam {String} [fields] Display only specific fields, e.g. fields=ID,Person(ID:Profile(ID:ImageUrl))
* @apiParam {String} access_token Oauth access token
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 Bad Request
* {
* "error": "[...]"
* }
*
*/
func (c ApiComment) Create() revel.Result {
var (
......@@ -123,16 +139,21 @@ func (c ApiComment) Create() revel.Result {
c.Params.Bind(&fields, "fields")
c.Params.Bind(&postID, "id")
if helpers.EmptyString(comment) {
c.Log.Error(TAG, "api", ERR_EMPTY_STRING)
return c.ApiError(http.StatusBadRequest, ERR_EMPTY_STRING)
}
user, err := models.CurrentUser(c.Params, c.Session)
if err != nil {
revel.AppLog.Error(err.Error())
return c.RenderApiError(err)
c.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return c.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
err = post.FindByID(postID)
if err != nil {
revel.AppLog.Error(err.Error())
return c.RenderApiError(err)
c.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return c.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
dispatcher := jobs.Dispatcher{
......
......@@ -23,6 +23,7 @@ import (
"gopkg.in/ganggo/ganggo.v0/app/jobs"
"gopkg.in/ganggo/ganggo.v0/app/helpers"
federation "gopkg.in/ganggo/federation.v0"
"net/http"
)
/**
......@@ -55,7 +56,7 @@ type ApiLike struct {
* @apiSuccess {String} TargetType Entity type e.g. Post, Comment
* @apiSuccess {Hash} Signature Signature structure
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -71,13 +72,14 @@ type ApiLike struct {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
*/
func (l ApiLike) Index() revel.Result {
var (
......@@ -88,8 +90,8 @@ func (l ApiLike) Index() revel.Result {
l.Params.Bind(&postID, "id")
err := likes.FindByPostID(postID)
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return l.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
return l.RenderJSON(likes)
......@@ -115,7 +117,7 @@ func (l ApiLike) Index() revel.Result {
* @apiSuccess {String} TargetType Entity type e.g. Post, Comment
* @apiSuccess {Hash} Signature Signature structure
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {
* "ID": 12,
......@@ -129,13 +131,26 @@ func (l ApiLike) Index() revel.Result {
* [...]
* }
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "[...]"
* }
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (l ApiLike) Create() revel.Result {
var (
......@@ -150,20 +165,20 @@ func (l ApiLike) Create() revel.Result {
err := post.FindByID(postID)
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_NOT_FOUND)
return l.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
user, err := models.CurrentUser(l.Params, l.Session)
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return l.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
guid, err := helpers.Uuid()
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return l.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
entityLike := federation.EntityLike{
......@@ -176,8 +191,8 @@ func (l ApiLike) Create() revel.Result {
err = like.Create(&entityLike)
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return l.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
// deliver to the network
......@@ -192,8 +207,8 @@ func (l ApiLike) Create() revel.Result {
var parentUser models.User
err = parentUser.FindByID(user.Person.UserID)
if err != nil {
revel.AppLog.Error(err.Error())
return l.RenderApiError(err)
l.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return l.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
dispatcher.ParentUser = &parentUser
}
......
......@@ -20,6 +20,7 @@ package controllers
import (
"github.com/revel/revel"
"gopkg.in/ganggo/ganggo.v0/app/models"
"net/http"
)
/**
......@@ -49,7 +50,7 @@ type ApiNotification struct {
* @apiSuccess {Number} PersonID Person database ID
* @apiSuccess {Number} UserID User database ID
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* [
* {
......@@ -64,26 +65,33 @@ type ApiNotification struct {
* }
* ]
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (n ApiNotification) Index() revel.Result {
user, err := models.CurrentUser(n.Params, n.Session)
if err != nil {
revel.AppLog.Error(err.Error())
return n.RenderApiError(err)
n.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return n.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
var notify models.Notifications
err = notify.FindUnreadByUserID(user.ID)
if err != nil {
revel.AppLog.Error(err.Error())
return n.RenderApiError(err)
n.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return n.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
return n.RenderJSON(notify)
......@@ -114,7 +122,7 @@ func (n ApiNotification) Show() revel.Result {
* @apiSuccess {Number} PersonID Person database ID
* @apiSuccess {Number} UserID User database ID
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {
* "ID": 12,
......@@ -127,19 +135,26 @@ func (n ApiNotification) Show() revel.Result {
* "TargetType": "Post"
* }
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* HTTP/1.1 404 Not Found
* @apiErrorExample {json} Unauthorized
* HTTP/1.1 401 Unauthorized
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (n ApiNotification) Update(id uint) revel.Result {
user, err := models.CurrentUser(n.Params, n.Session)
if err != nil {
revel.AppLog.Error(err.Error())
return n.RenderApiError(err)
n.Log.Error(TAG, "db", err, "api", ERR_UNAUTHORIZED)
return n.ApiError(http.StatusUnauthorized, ERR_UNAUTHORIZED)
}
notify := models.Notification{
......@@ -149,8 +164,8 @@ func (n ApiNotification) Update(id uint) revel.Result {
}
err = notify.Update()
if err != nil {
revel.AppLog.Error(err.Error())
return n.RenderApiError(err)
n.Log.Error(TAG, "db", err, "api", ERR_SERVER)
return n.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
return n.RenderJSON(notify)
......
......@@ -21,6 +21,8 @@ import (
"github.com/revel/revel"
"gopkg.in/ganggo/ganggo.v0/app/models"
"gopkg.in/ganggo/ganggo.v0/app/helpers"
apiHelpers "gopkg.in/ganggo/api.v0/app/helpers"
"net/http"
)
type TokenResult struct {
......@@ -39,6 +41,8 @@ type TokenString string
*/
type ApiOAuth struct {
*revel.Controller
ApiHelper
}
/**
......@@ -53,19 +57,32 @@ type ApiOAuth struct {
*
* @apiSuccess {String} token Access token
*
* @apiSuccessExample Success-Response:
* @apiSuccessExample {json} Success-Response
* HTTP/1.1 200 OK
* {
* "token": "5b5d5b4f7044e3444db73504e8b08be8"
* }
*
* @apiError error Contains recent error message
* @apiError (Errors) {String} error Contains the recent error message
*
* @apiErrorExample Error-Response:
* @apiErrorExample {json} NotFound
* HTTP/1.1 404 Not Found
* {
* "error": "Error 1052: Column 'xyz' not found"
* "error": "[...]"
* }
*
* @apiErrorExample {json} BadRequest
* HTTP/1.1 400 Bad Request
* {
* "error": "[...]"
* }
*
* @apiErrorExample {json} ServerError
* HTTP/1.1 500 Internal Server Error
* {
* "error": "[...]"
* }
*
*/
func (o ApiOAuth) Create() revel.Result {
var (
......@@ -83,42 +100,32 @@ func (o ApiOAuth) Create() revel.Result {
o.Params.Bind(&password, "password")
o.Params.Bind(&clientID, "client_id")
if clientID == "" {
o.Log.Error("client_id is empty", "client_id", clientID)
return o.RenderJSON(TokenResult{
Error: TokenString("client_id is empty!"),
})
if apiHelpers.EmptyString(clientID) {
o.Log.Error(TAG, "api", ERR_EMPTY_STRING)
return o.ApiError(http.StatusBadRequest, ERR_EMPTY_STRING)
}
if grantType != "password" {
o.Log.Error("grant_type not supported", "grant_type", grantType)
return o.RenderJSON(TokenResult{
Error: TokenString("grant_type not supported!"),
})
o.Log.Error(TAG, "api", ERR_GRANT_TYPE)
return o.ApiError(http.StatusBadRequest, ERR_GRANT_TYPE)
}
err := user.FindByUsername(username)
if err != nil {
o.Log.Error(err.Error())
return o.RenderJSON(TokenResult{
Error: TokenString(err.Error()),
})
o.Log.Error(TAG, "err", err, "api", ERR_NOT_FOUND)
return o.ApiError(http.StatusNotFound, ERR_NOT_FOUND)
}
if !helpers.CheckHash(password, user.EncryptedPassword) {
o.Log.Error("Password did not match", "username", username)
return o.RenderJSON(TokenResult{
Error: TokenString("password did not match!"),
})
o.Log.Error(TAG, "api", ERR_PASSWORD)
return o.ApiError(http.StatusBadRequest, ERR_PASSWORD)
}
token.ClientID = clientID
tokenVal, err := helpers.Token()
if err != nil {
o.Log.Error(err.Error())
return o.RenderJSON(TokenResult{
Error: TokenString(err.Error()),
})
o.Log.Error(TAG, "err", err, "api", ERR_SERVER)
return o.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
token.Token = tokenVal
token.UserID = user.ID
......@@ -127,10 +134,8 @@ func (o ApiOAuth) Create() revel.Result {
if err != nil {
err = token.FindByUserIDAndClientID(user.ID, clientID)
if err != nil {
o.Log.Error(err.Error())
return o.RenderJSON(TokenResult{
Error: TokenString(err.Error()),
})
o.Log.Error(TAG, "err", err, "api", ERR_SERVER)
return o.ApiError(http.StatusInternalServerError, ERR_SERVER)
}
}
......@@ -148,33 +153,36 @@ func (o ApiOAuth) Create() revel.Result {
*
* @apiSuccess {String} token Access token
*
* @apiSuccessExample Success-Response: