Skip to content

Commit

Permalink
Merge pull request #13 from stripe/brandur-pretty-print
Browse files Browse the repository at this point in the history
Pretty print responses when request is from cURL
  • Loading branch information
brandur-stripe authored Aug 15, 2017
2 parents 753aa06 + 2b1f757 commit a591531
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 12 deletions.
5 changes: 5 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func initTestSpec() {
{
In: "body",
Schema: &spec.JSONSchema{
Properties: map[string]*spec.JSONSchema{
"amount": {
Type: []string{"integer"},
},
},
RawFields: map[string]interface{}{
"properties": map[string]interface{}{
"amount": map[string]interface{}{
Expand Down
35 changes: 24 additions & 11 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,21 @@ func (s *StubServer) HandleRequest(w http.ResponseWriter, r *http.Request) {

auth := r.Header.Get("Authorization")
if !validateAuth(auth) {
writeResponse(w, start, http.StatusUnauthorized,
writeResponse(w, r, start, http.StatusUnauthorized,
fmt.Sprintf(invalidAuthorization, auth))
return
}

route := s.routeRequest(r)
if route == nil {
writeResponse(w, start, http.StatusNotFound, nil)
writeResponse(w, r, start, http.StatusNotFound, nil)
return
}

response, ok := route.method.Responses["200"]
if !ok {
log.Printf("Couldn't find 200 response in spec")
writeResponse(w, start, http.StatusInternalServerError, nil)
writeResponse(w, r, start, http.StatusInternalServerError, nil)
return
}

Expand All @@ -119,7 +119,7 @@ func (s *StubServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
formBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Couldn't read request body: %v", err)
writeResponse(w, start, http.StatusInternalServerError, nil)
writeResponse(w, r, start, http.StatusInternalServerError, nil)
return
}
r.Body.Close()
Expand All @@ -128,7 +128,7 @@ func (s *StubServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
requestData, err := parser.ParseFormString(formString)
if err != nil {
log.Printf("Couldn't parse query/body: %v", err)
writeResponse(w, start, http.StatusInternalServerError, nil)
writeResponse(w, r, start, http.StatusInternalServerError, nil)
return
}

Expand All @@ -143,13 +143,14 @@ func (s *StubServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
// support validation all verbs, and much more simply.
requestSchema := bodyParameterSchema(route.method)
if requestSchema != nil {
log.Printf("requestSchema = %+v\n", requestSchema)
coercer.CoerceParams(requestSchema, requestData)

err := route.validator.Validate(requestData)
if err != nil {
log.Printf("Validation error: %v", err)
responseData := fmt.Sprintf("Request error: %v", err)
writeResponse(w, start, http.StatusBadRequest, responseData)
writeResponse(w, r, start, http.StatusBadRequest, responseData)
return
}
}
Expand All @@ -163,10 +164,10 @@ func (s *StubServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
responseData, err := generator.Generate(response.Schema, r.URL.Path, expansions)
if err != nil {
log.Printf("Couldn't generate response: %v", err)
writeResponse(w, start, http.StatusInternalServerError, nil)
writeResponse(w, r, start, http.StatusInternalServerError, nil)
return
}
writeResponse(w, start, http.StatusOK, responseData)
writeResponse(w, r, start, http.StatusOK, responseData)
}

func (s *StubServer) initializeRouter() error {
Expand Down Expand Up @@ -308,15 +309,27 @@ func getValidator(method *spec.Method) (*jsval.JSVal, error) {
return nil, nil
}

func writeResponse(w http.ResponseWriter, start time.Time, status int, data interface{}) {
func isCurl(userAgent string) bool {
return strings.HasPrefix(userAgent, "curl/")
}

func writeResponse(w http.ResponseWriter, r *http.Request, start time.Time, status int, data interface{}) {
if data == nil {
data = http.StatusText(status)
}

encodedData, err := json.Marshal(&data)
var encodedData []byte
var err error

if isCurl(r.Header.Get("User-Agent")) {
encodedData, err = json.Marshal(&data)
} else {
encodedData, err = json.MarshalIndent(&data, "", " ")
}

if err != nil {
log.Printf("Error serializing response: %v", err)
writeResponse(w, start, http.StatusInternalServerError, nil)
writeResponse(w, r, start, http.StatusInternalServerError, nil)
return
}

Expand Down
43 changes: 42 additions & 1 deletion server_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"encoding/base64"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -42,6 +43,25 @@ func TestStubServer_ParameterValidation(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
}

func TestStubServer_FormatsForCurl(t *testing.T) {
server := getStubServer(t)

req := httptest.NewRequest("POST", "https://stripe.com/v1/charges",
bytes.NewBufferString("amount=123&currency=usd"))
req.Header.Set("Authorization", "Bearer sk_test_123")
w := httptest.NewRecorder()
server.HandleRequest(w, req)

resp := w.Result()
body, err := ioutil.ReadAll(resp.Body)
assert.NoError(t, err)

// Note the two spaces in front of "id" which indicate that our JSON is
// pretty printed.
assert.Contains(t, string(body), ` "id"`)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}

func TestStubServer_RoutesRequest(t *testing.T) {
server := getStubServer(t)
var route *stubServerRoute
Expand Down Expand Up @@ -116,6 +136,27 @@ func TestGetValidator_NoSuitableParameter(t *testing.T) {
assert.Nil(t, validator)
}

func TestIsCurl(t *testing.T) {
testCases := []struct {
userAgent string
want bool
}{
{"curl/7.51.0", true},

// false because it's not something (to my knowledge) that cURL would
// ever return
{"curl", false},

{"Mozilla", false},
{"", false},
}
for _, tc := range testCases {
t.Run(tc.userAgent, func(t *testing.T) {
assert.Equal(t, tc.want, isCurl(tc.userAgent))
})
}
}

func TestParseExpansionLevel(t *testing.T) {
testCases := []struct {
expansions []string
Expand Down Expand Up @@ -199,7 +240,7 @@ func encode64(s string) string {
}

func getStubServer(t *testing.T) *StubServer {
server := &StubServer{spec: &testSpec}
server := &StubServer{spec: &testSpec, fixtures: &testFixtures}
err := server.initializeRouter()
assert.NoError(t, err)
return server
Expand Down

0 comments on commit a591531

Please sign in to comment.