initial commits

master
Charles Iliya Krempeaux 2023-09-26 12:28:29 +09:00
parent 49778ecc54
commit 2f0bb9cf5e
2 changed files with 300 additions and 0 deletions

97
error.go 100644
View File

@ -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...)
}

203
errorjson_test.go 100644
View File

@ -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
}
}
}