Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for default http-messages #5

Merged
merged 3 commits into from
Jun 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,34 @@ See [here](https://httpstatuses.com/) for a complete list of HTTP responses, alo

Please submit a PR if you want to add to this list. Only the most common response types have been included.

## To Long, Don't Write

Sometimes you don't need to return a specific content-message but don't want the response body to be empty.
In this case you can use the `DefaultMessage()` for responding with json containing the default message for the corresponding status code.

```go
package main

import (
"net/http"
resp "github.com/nicklaw5/go-respond"
)

func main() {
http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
// ...
if !authenticated {
resp.NewResponse(w).DefaultMessage().
Unauthorized(nil)
}
// ...
})
http.ListenAndServe(":8080", nil)
}
```

Would respond with `{"status":401,"message":"Unauthorized"}`

## Handling Errors

The best option for handling errors that may occur while marshalling the JSON response, is to use [Negroni's Recovery middleware](https://github.com/urfave/negroni#recovery). Here's an example:
Expand Down
26 changes: 23 additions & 3 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ import (

// Response is the HTTP response
type Response struct {
Writer http.ResponseWriter
Headers map[string]string
Writer http.ResponseWriter
Headers map[string]string
DefMessage bool
}

// DefaultMessageResponse is for transporting a default http message
type DefaultMessageResponse struct {
Status int `json:"status"`
Message string `json:"message"`
}

// NewResponse creates and returns a new response
Expand All @@ -21,6 +28,11 @@ func NewResponse(w http.ResponseWriter) *Response {
}
}

func (resp *Response) DefaultMessage() *Response {
resp.DefMessage = true
return resp
}

// DeleteHeader deletes a single header from the response
func (resp *Response) DeleteHeader(key string) *Response {
resp.Writer.Header().Del(key)
Expand All @@ -41,16 +53,24 @@ func (resp *Response) writeResponse(code int, v interface{}) error {

resp.writeStatusCode(code)

if v == nil && resp.DefMessage {
v = DefaultMessageResponse{
Status: code,
Message: http.StatusText(code),
}
}

if v != nil {
body, err := json.Marshal(v)
if err != nil {
panic(err)
}

// can just return an error when connection is hijacked or content-size is longer then declared.
if _, err := resp.Writer.Write(body); err != nil {
panic(err)
}
}

return nil
}

Expand Down
36 changes: 36 additions & 0 deletions response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,42 @@ func validateResponseHeader(responseHeaderValue string, expectedHeaderValue stri
return nil
}

func TestDefaultMessage(t *testing.T) {
t.Parallel()

req := newRequest(t, "GET")

rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
NewResponse(w).DefaultMessage().
Unauthorized(nil)
})
handler.ServeHTTP(rr, req)

if err := validateResponseBody(rr.Body.String(), "{\"status\":401,\"message\":\"Unauthorized\"}"); err != nil {
t.Fatal(err)
}
}

func TestRespondInvalidType(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("responding with invalid type (channel) should have caused a panic")
}
}()

t.Parallel()

req := newRequest(t, "GET")

rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
NewResponse(w).DefaultMessage().
Unauthorized(make(chan int))
})
handler.ServeHTTP(rr, req)
}

func TestContentTypeHeader(t *testing.T) {
t.Parallel()

Expand Down