initial commits
parent
49778ecc54
commit
2f0bb9cf5e
|
@ -0,0 +1,97 @@
|
||||||
|
package mstdn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"sourcecode.social/reiver/go-opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func errorJSON(writer io.Writer, statusCode int, msg ...interface{}) {
|
||||||
|
if nil == writer {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// short error message.
|
||||||
|
var short string
|
||||||
|
{
|
||||||
|
var shortErrorMessage opt.Optional[string]
|
||||||
|
|
||||||
|
shortErrorMessage.WhenNothing(func(){
|
||||||
|
if 1 <= len(msg) {
|
||||||
|
shortErrorMessage = opt.Something(fmt.Sprint(msg[0]))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
shortErrorMessage.WhenNothing(func(){
|
||||||
|
shortErrorMessage = opt.Something(http.StatusText(statusCode))
|
||||||
|
})
|
||||||
|
|
||||||
|
shortErrorMessage.WhenSomething(func(value string){
|
||||||
|
short = value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var long opt.Optional[string]
|
||||||
|
{
|
||||||
|
if 2 <= len(msg) {
|
||||||
|
long = opt.Something(fmt.Sprint(msg[1:]...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var array [512]byte
|
||||||
|
var buffer []byte = array[:0]
|
||||||
|
{
|
||||||
|
|
||||||
|
buffer = append(buffer, "{"...)
|
||||||
|
buffer = append(buffer, `"error":`...)
|
||||||
|
{
|
||||||
|
// This should never return an error since we are passing a string.
|
||||||
|
marshaled, _ := json.Marshal(short)
|
||||||
|
|
||||||
|
buffer = append(buffer, marshaled...)
|
||||||
|
}
|
||||||
|
|
||||||
|
long.WhenSomething(func(value string){
|
||||||
|
buffer = append(buffer, `,"error_description":`...)
|
||||||
|
|
||||||
|
// This should never return an error since we are passing a string.
|
||||||
|
marshaled, _ := json.Marshal(value)
|
||||||
|
|
||||||
|
buffer = append(buffer, marshaled...)
|
||||||
|
})
|
||||||
|
buffer = append(buffer, "}"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error responds to the request with the specified error message and HTTP code.
|
||||||
|
// The response will be in JSON (application/json; charset=utf-8).
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// var statusCode int = http.StatusUnauthorized
|
||||||
|
// var shortErrorMessage = http.StatusText(http.StatusUnauthorized)
|
||||||
|
// var longErrorMessage = "Access Denied!!! — you can keep on knocking but you can't come in"
|
||||||
|
//
|
||||||
|
// mstdn.Error(resp, statusCode, shortErrorMessage, longErrorMessage)
|
||||||
|
//
|
||||||
|
// Responds with:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "error":"Unauthorized",
|
||||||
|
// "error_description":"Access Defined!!!! — you can keep on knocking but you can't come in"
|
||||||
|
// }
|
||||||
|
func Error(resp http.ResponseWriter, statusCode int, msg ...interface{}) {
|
||||||
|
if nil == resp {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteHeader(statusCode)
|
||||||
|
resp.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
errorJSON(resp, statusCode, msg...)
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package mstdn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestErrorJSON(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct{
|
||||||
|
StatusCode int
|
||||||
|
Message []interface{}
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
StatusCode: 400,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Bad Request"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 401,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Unauthorized"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 403,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Forbidden"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 404,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Not Found"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 422,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Unprocessable Entity"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 429,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Too Many Requests"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 500,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Internal Server Error"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 503,
|
||||||
|
Message: []interface{}{},
|
||||||
|
Expected: `{"error":"Service Unavailable"}`,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
StatusCode: 400,
|
||||||
|
Message: []interface{}{"very bad request"},
|
||||||
|
Expected: `{"error":"very bad request"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 401,
|
||||||
|
Message: []interface{}{"get out of here"},
|
||||||
|
Expected: `{"error":"get out of here"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 403,
|
||||||
|
Message: []interface{}{"no!!!!"},
|
||||||
|
Expected: `{"error":"no!!!!"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 404,
|
||||||
|
Message: []interface{}{"huh?"},
|
||||||
|
Expected: `{"error":"huh?"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 422,
|
||||||
|
Message: []interface{}{"WTF?"},
|
||||||
|
Expected: `{"error":"WTF?"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 429,
|
||||||
|
Message: []interface{}{"f-off"},
|
||||||
|
Expected: `{"error":"f-off"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 500,
|
||||||
|
Message: []interface{}{"crap!"},
|
||||||
|
Expected: `{"error":"crap!"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 503,
|
||||||
|
Message: []interface{}{"nope"},
|
||||||
|
Expected: `{"error":"nope"}`,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
StatusCode: 400,
|
||||||
|
Message: []interface{}{"very bad request", "you have been naughty"},
|
||||||
|
Expected: `{"error":"very bad request","error_description":"you have been naughty"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 401,
|
||||||
|
Message: []interface{}{"get out of here", "access denied!!! — you can keep on knocking but you can't come in"},
|
||||||
|
Expected: `{"error":"get out of here","error_description":"access denied!!! — you can keep on knocking but you can't come in"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 403,
|
||||||
|
Message: []interface{}{"no!!!!", "go away"},
|
||||||
|
Expected: `{"error":"no!!!!","error_description":"go away"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 404,
|
||||||
|
Message: []interface{}{"huh?", "what are you talking about"},
|
||||||
|
Expected: `{"error":"huh?","error_description":"what are you talking about"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 422,
|
||||||
|
Message: []interface{}{"WTF?", "i don't understand the words coming out of your mouth"},
|
||||||
|
Expected: `{"error":"WTF?","error_description":"i don't understand the words coming out of your mouth"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 429,
|
||||||
|
Message: []interface{}{"f-off", "slow it down, back it up"},
|
||||||
|
Expected: `{"error":"f-off","error_description":"slow it down, back it up"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 500,
|
||||||
|
Message: []interface{}{"crap!", "i f-ed up"},
|
||||||
|
Expected: `{"error":"crap!","error_description":"i f-ed up"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 503,
|
||||||
|
Message: []interface{}{"nope", "it not workie"},
|
||||||
|
Expected: `{"error":"nope","error_description":"it not workie"}`,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
StatusCode: 400,
|
||||||
|
Message: []interface{}{"very bad request", "you have been naughty", " :-)"},
|
||||||
|
Expected: `{"error":"very bad request","error_description":"you have been naughty :-)"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 401,
|
||||||
|
Message: []interface{}{"get out of here", "access denied!!! — you can keep on knocking but you can't come in", "."},
|
||||||
|
Expected: `{"error":"get out of here","error_description":"access denied!!! — you can keep on knocking but you can't come in."}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 403,
|
||||||
|
Message: []interface{}{"no!!!!", "go away", "!"},
|
||||||
|
Expected: `{"error":"no!!!!","error_description":"go away!"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 404,
|
||||||
|
Message: []interface{}{"huh?", "what are you talking about", "?"},
|
||||||
|
Expected: `{"error":"huh?","error_description":"what are you talking about?"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 422,
|
||||||
|
Message: []interface{}{"WTF?", "i don't understand the words coming out of your mouth", "."},
|
||||||
|
Expected: `{"error":"WTF?","error_description":"i don't understand the words coming out of your mouth."}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 429,
|
||||||
|
Message: []interface{}{"f-off", "slow it down, back it up", "."},
|
||||||
|
Expected: `{"error":"f-off","error_description":"slow it down, back it up."}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 500,
|
||||||
|
Message: []interface{}{"crap!", "i f-ed up", " :-("},
|
||||||
|
Expected: `{"error":"crap!","error_description":"i f-ed up :-("}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StatusCode: 503,
|
||||||
|
Message: []interface{}{"nope", "it not workie", "."},
|
||||||
|
Expected: `{"error":"nope","error_description":"it not workie."}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for testNumber, test := range tests {
|
||||||
|
|
||||||
|
var actualBuffer strings.Builder
|
||||||
|
|
||||||
|
errorJSON(&actualBuffer, test.StatusCode, test.Message...)
|
||||||
|
|
||||||
|
actual := actualBuffer.String()
|
||||||
|
expected := test.Expected
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("For test #%d, the actual value is not what was expected.", testNumber)
|
||||||
|
t.Logf("EXPECTED:\n%s", expected)
|
||||||
|
t.Logf("ACTUAL:\n%s", actual)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue