diff --git a/apidocs/openapi.yaml b/apidocs/openapi.yaml index 9b965c5633c..ab932931706 100644 --- a/apidocs/openapi.yaml +++ b/apidocs/openapi.yaml @@ -15,6 +15,12 @@ security: [] components: schemas: + Error: + type: object + properties: + error: + type: string + GlobalConf: type: object properties: @@ -633,8 +639,16 @@ paths: $ref: '#/components/schemas/GlobalConf' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/global/patch: patch: @@ -652,8 +666,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/pathdefaults/get: get: @@ -669,8 +691,16 @@ paths: $ref: '#/components/schemas/PathConf' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/pathdefaults/patch: patch: @@ -688,8 +718,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/list: get: @@ -718,8 +756,16 @@ paths: $ref: '#/components/schemas/PathConfList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/get/{name}: get: @@ -742,8 +788,16 @@ paths: $ref: '#/components/schemas/PathConf' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/add/{name}: post: @@ -768,8 +822,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/patch/{name}: patch: @@ -794,8 +856,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/replace/{name}: post: @@ -820,8 +890,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/config/paths/delete/{name}: delete: @@ -840,8 +918,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/hlsmuxers/list: get: @@ -870,8 +956,16 @@ paths: $ref: '#/components/schemas/HLSMuxerList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/hlsmuxers/get/{name}: get: @@ -894,8 +988,16 @@ paths: $ref: '#/components/schemas/HLSMuxer' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/paths/list: get: @@ -924,8 +1026,16 @@ paths: $ref: '#/components/schemas/PathList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/paths/get/{name}: get: @@ -948,8 +1058,16 @@ paths: $ref: '#/components/schemas/Path' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspconns/list: get: @@ -978,8 +1096,16 @@ paths: $ref: '#/components/schemas/RTSPConnList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspconns/get/{id}: get: @@ -1002,8 +1128,16 @@ paths: $ref: '#/components/schemas/RTSPConn' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspsessions/list: get: @@ -1032,8 +1166,16 @@ paths: $ref: '#/components/schemas/RTSPSessionList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspsessions/get/{id}: get: @@ -1056,8 +1198,16 @@ paths: $ref: '#/components/schemas/RTSPSession' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspsessions/kick/{id}: post: @@ -1076,8 +1226,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspsconns/list: get: @@ -1106,8 +1264,16 @@ paths: $ref: '#/components/schemas/RTSPConnList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspsconns/get/{id}: get: @@ -1130,8 +1296,16 @@ paths: $ref: '#/components/schemas/RTSPConn' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspssessions/list: get: @@ -1160,8 +1334,16 @@ paths: $ref: '#/components/schemas/RTSPSessionList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspssessions/get/{id}: get: @@ -1184,8 +1366,16 @@ paths: $ref: '#/components/schemas/RTSPSession' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtspssessions/kick/{id}: post: @@ -1204,8 +1394,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpconns/list: get: @@ -1234,8 +1432,16 @@ paths: $ref: '#/components/schemas/RTMPConnList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpconns/get/{id}: get: @@ -1258,8 +1464,16 @@ paths: $ref: '#/components/schemas/RTMPConn' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpconns/kick/{id}: post: @@ -1278,8 +1492,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpsconns/list: get: @@ -1308,8 +1530,16 @@ paths: $ref: '#/components/schemas/RTMPConnList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpsconns/get/{id}: get: @@ -1332,8 +1562,16 @@ paths: $ref: '#/components/schemas/RTMPConn' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/rtmpsconns/kick/{id}: post: @@ -1352,8 +1590,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/srtconns/list: get: @@ -1382,8 +1628,16 @@ paths: $ref: '#/components/schemas/SRTConnList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/srtconns/get/{id}: get: @@ -1406,8 +1660,16 @@ paths: $ref: '#/components/schemas/SRTConn' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/srtconns/kick/{id}: post: @@ -1426,8 +1688,16 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/webrtcsessions/list: get: @@ -1456,8 +1726,16 @@ paths: $ref: '#/components/schemas/WebRTCSessionList' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/webrtcsessions/get/{id}: get: @@ -1480,8 +1758,16 @@ paths: $ref: '#/components/schemas/WebRTCSession' '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /v3/webrtcsessions/kick/{id}: post: @@ -1500,5 +1786,13 @@ paths: description: the request was successful. '400': description: invalid request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' diff --git a/internal/core/api.go b/internal/core/api.go index 098bad891ce..7be9c81149d 100644 --- a/internal/core/api.go +++ b/internal/core/api.go @@ -277,14 +277,24 @@ func (a *api) Log(level logger.Level, format string, args ...interface{}) { // error coming from something the user inserted into the request. func (a *api) writeUserError(ctx *gin.Context, err error) { + // show error in logs a.Log(logger.Error, err.Error()) - ctx.AbortWithStatus(http.StatusBadRequest) + + // send error in response + ctx.JSON(http.StatusBadRequest, &apiError{ + Error: err.Error(), + }) } // error coming from the server. func (a *api) writeServerError(ctx *gin.Context, err error) { + // show error in logs a.Log(logger.Error, err.Error()) - ctx.AbortWithStatus(http.StatusInternalServerError) + + // send error in response + ctx.JSON(http.StatusInternalServerError, &apiError{ + Error: err.Error(), + }) } func (a *api) onConfigGlobalGet(ctx *gin.Context) { diff --git a/internal/core/api_defs.go b/internal/core/api_defs.go index c791507be0f..edf6036ad68 100644 --- a/internal/core/api_defs.go +++ b/internal/core/api_defs.go @@ -8,6 +8,10 @@ import ( "github.com/bluenviron/mediamtx/internal/conf" ) +type apiError struct { + Error string `json:"error"` +} + type apiPathConfList struct { ItemCount int `json:"itemCount"` PageCount int `json:"pageCount"` diff --git a/internal/core/api_test.go b/internal/core/api_test.go index 2dbbc2b55f4..f45ecdfa8ef 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -64,6 +64,13 @@ func checkClose(t *testing.T, closeFunc func() error) { require.NoError(t, closeFunc()) } +func checkError(t *testing.T, msg string, body io.Reader) { + var resErr map[string]interface{} + err := json.NewDecoder(body).Decode(&resErr) + require.NoError(t, err) + require.Equal(t, map[string]interface{}{"error": msg}, resErr) +} + func httpRequest(t *testing.T, hc *http.Client, method string, ur string, in interface{}, out interface{}) { buf := func() io.Reader { if in == nil { @@ -184,7 +191,9 @@ func TestAPIConfigGlobalPatchUnknownField(t *testing.T) { res, err := hc.Do(req) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + checkError(t, "json: unknown field \"test\"", res.Body) }() } @@ -320,7 +329,9 @@ func TestAPIConfigPathsAddUnknownField(t *testing.T) { res, err := hc.Do(req) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + checkError(t, "json: unknown field \"test\"", res.Body) }() } @@ -398,7 +409,9 @@ func TestAPIConfigPathsDelete(t *testing.T) { res, err := hc.Do(req) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + checkError(t, "path configuration not found", res.Body) }() } @@ -650,7 +663,9 @@ func TestAPIPathsGet(t *testing.T) { res, err := hc.Get("http://localhost:9997/v3/paths/get/" + pathName) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + checkError(t, "path not found", res.Body) } }) } @@ -1331,7 +1346,19 @@ func TestAPIProtocolGetNotFound(t *testing.T) { res, err := hc.Do(req) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + + switch ca { + case "rtsp conns", "rtsps conns", "rtmp", "rtmps", "srt": + checkError(t, "connection not found", res.Body) + + case "rtsp sessions", "rtsps sessions", "webrtc": + checkError(t, "session not found", res.Body) + + case "hls": + checkError(t, "muxer not found", res.Body) + } }() }) } @@ -1543,7 +1570,19 @@ func TestAPIProtocolKickNotFound(t *testing.T) { res, err := hc.Do(req) require.NoError(t, err) defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + + switch ca { + case "rtsp conns", "rtsps conns", "rtmp", "rtmps", "srt": + checkError(t, "connection not found", res.Body) + + case "rtsp sessions", "rtsps sessions", "webrtc": + checkError(t, "session not found", res.Body) + + case "hls": + checkError(t, "muxer not found", res.Body) + } }() }) }