Skip to content

Commit

Permalink
Added a teapot and improved problem responses
Browse files Browse the repository at this point in the history
  • Loading branch information
p0t4t0sandwich committed Apr 13, 2024
1 parent 731653f commit 33b0c15
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 29 deletions.
15 changes: 12 additions & 3 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"github.com/NeuralNexusDev/neuralnexus-api/modules/cct_turtle"
"github.com/NeuralNexusDev/neuralnexus-api/modules/mcstatus"
"github.com/NeuralNexusDev/neuralnexus-api/modules/petpictures"
"github.com/NeuralNexusDev/neuralnexus-api/modules/projects"
"github.com/NeuralNexusDev/neuralnexus-api/modules/switchboard"
"github.com/NeuralNexusDev/neuralnexus-api/modules/teapot"
"github.com/NeuralNexusDev/neuralnexus-api/routes"
"github.com/rs/cors"
)
Expand All @@ -33,15 +35,17 @@ func NewAPIServer(address string, usingUDS bool) *APIServer {
}
}

// Run - Start the API server
func (s *APIServer) Run() error {
// Setup - Setup the API server
func (s *APIServer) Setup() http.Handler {
routerStack := routes.CreateStack(
authroutes.ApplyRoutes,
beenamegenerator.ApplyRoutes,
cct_turtle.ApplyRoutes,
mcstatus.ApplyRoutes,
petpictures.ApplyRoutes,
projects.ApplyRoutes,
switchboard.ApplyRoutes,
teapot.ApplyRoutes,
)

middlewareStack := middleware.CreateStack(
Expand All @@ -57,9 +61,14 @@ func (s *APIServer) Run() error {
v1 := http.NewServeMux()
v1.Handle("/api/v1/", http.StripPrefix("/api/v1", router))

return middlewareStack(v1)
}

// Run - Start the API server
func (s *APIServer) Run() error {
server := http.Server{
Addr: s.Address,
Handler: middlewareStack(v1),
Handler: s.Setup(),
}

if s.UsingUDS {
Expand Down
5 changes: 3 additions & 2 deletions modules/projects/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ func ConvertToFMLFormat(gitHubReleasesURL string, releases []Release) map[string
}

// -------------- Routes --------------

// ApplyRoutes - Apply the routes
func ApplyRoutes(mux *http.ServeMux) *http.ServeMux {
func ApplyRoutes(mux, authedMux *http.ServeMux) (*http.ServeMux, *http.ServeMux) {
mux.HandleFunc("GET /projects/releases/{group}/{project}", GetReleasesHandler)
return mux
return mux, authedMux
}

// GetReleasesHandler - Get the releases for a project
Expand Down
23 changes: 23 additions & 0 deletions modules/teapot/teapot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package teapot

import (
"net/http"

"github.com/NeuralNexusDev/neuralnexus-api/responses"
)

// -------------- Routes --------------

// ApplyRoutes - Apply the routes
func ApplyRoutes(mux, authedMux *http.ServeMux) (*http.ServeMux, *http.ServeMux) {
mux.HandleFunc("GET /teapot", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
responses.NewProblemResponse(
"about:blank",
http.StatusTeapot,
"I'm a teapot",
"I'm a little teapot, short and stout\nHere is my handle, here is my spout\n",
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418",
).SendAndEncodeProblem(w, r)
}))
return mux, authedMux
}
18 changes: 18 additions & 0 deletions responses/problem.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package responses

import (
"encoding/json"
"encoding/xml"
"net/http"
)

// -------------- Structs --------------
// ProblemResponse -- Defined by https://www.rfc-editor.org/rfc/rfc9457.html#section-3
type ProblemResponse struct {
Expand All @@ -20,3 +26,15 @@ func NewProblemResponse(Type string, Status int, Title string, Detail string, In
Instance: Instance,
}
}

// SendAndEncodeProblem -- Send a ProblemResponse as JSON or XML
func (problem *ProblemResponse) SendAndEncodeProblem(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(problem.Status)
if r.Header.Get("Content-Type") == "application/xml" {
w.Header().Set("Content-Type", "application/problem+xml")
xml.NewEncoder(w).Encode(problem)
} else {
w.Header().Set("Content-Type", "application/problem+json")
json.NewEncoder(w).Encode(problem)
}
}
32 changes: 8 additions & 24 deletions responses/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,71 +28,55 @@ func DecodeStruct[T any](r *http.Request, data *T) error {
return json.NewDecoder(r.Body).Decode(data)
}

// SendAndEncodeProblem -- Send a ProblemResponse as JSON or XML
func SendAndEncodeProblem(w http.ResponseWriter, r *http.Request, problem *ProblemResponse) {
w.WriteHeader(problem.Status)
if r.Header.Get("Content-Type") == "application/xml" {
w.Header().Set("Content-Type", "application/problem+xml")
xml.NewEncoder(w).Encode(problem)
} else {
w.Header().Set("Content-Type", "application/problem+json")
json.NewEncoder(w).Encode(problem)
}
}

// SendAndEncodeBadRequest - Send and encode an invalid input problem
func SendAndEncodeBadRequest(w http.ResponseWriter, r *http.Request, message string) {
problem := NewProblemResponse(
NewProblemResponse(
"about:blank",
http.StatusBadRequest,
"Bad Request",
message,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400",
)
SendAndEncodeProblem(w, r, problem)
).SendAndEncodeProblem(w, r)
}

// SendAndEncodeForbidden -- Send a ForbiddenResponse as JSON or XML
func SendAndEncodeForbidden(w http.ResponseWriter, r *http.Request, message string) {
if message == "" {
message = "You do not have permission to access this resource."
}
problem := NewProblemResponse(
NewProblemResponse(
"about:blank",
http.StatusForbidden,
"Forbidden",
message,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403",
)
SendAndEncodeProblem(w, r, problem)
).SendAndEncodeProblem(w, r)
}

// SendAndEncodeNotFound -- Send a NotFoundResponse as JSON or XML
func SendAndEncodeNotFound(w http.ResponseWriter, r *http.Request, message string) {
if message == "" {
message = "The requested resource could not be found."
}
problem := NewProblemResponse(
NewProblemResponse(
"about:blank",
http.StatusNotFound,
"Not Found",
message,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
)
SendAndEncodeProblem(w, r, problem)
).SendAndEncodeProblem(w, r)
}

// SendAndEncodeInternalServerError -- Send an InternalServerErrorResponse as JSON or XML
func SendAndEncodeInternalServerError(w http.ResponseWriter, r *http.Request, message string) {
if message == "" {
message = "An internal server error occurred."
}
problem := NewProblemResponse(
NewProblemResponse(
"about:blank",
http.StatusInternalServerError,
"Internal Server Error",
message,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500",
)
SendAndEncodeProblem(w, r, problem)
).SendAndEncodeProblem(w, r)
}

0 comments on commit 33b0c15

Please sign in to comment.