Skip to content

Commit

Permalink
Merge pull request #88 from tsawler/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
tsawler committed Apr 6, 2023
2 parents d9d4587 + 99f6f5d commit f5707c1
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 11 deletions.
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The included tools are:
- Write JSON
- Produce a JSON encoded error response
- Write XML
- Read XML
- Upload a file to a specified directory
- Download a static file
- Get a random string of length n
Expand Down
35 changes: 31 additions & 4 deletions tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const randomStringSource = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
// to all the exported methods with the receiver type *Tools.
type Tools struct {
MaxJSONSize int // maximum size of JSON file we'll process
MaxXMLSize int // maximum size of XML file we'll process
MaxFileSize int // maximum size of uploaded files in bytes
AllowedFileTypes []string // allowed file types for upload (e.g. image/jpeg)
AllowUnknownFields bool // if set to true, allow unknown fields in JSON
Expand All @@ -41,11 +42,11 @@ type XMLResponse struct {
Data interface{} `xml:"data,omitempty"`
}

// ReadJSON tries to read the body of a request and converts it into JSON.
// ReadJSON tries to read the body of a request and converts it from JSON to a variable.
func (t *Tools) ReadJSON(w http.ResponseWriter, r *http.Request, data interface{}) error {
maxBytes := 1024 * 1024 // one megabyte

// if MaxJSONSize is set, use that value instead of default
// if MaxJSONSize is set, use that value instead of default.
if t.MaxJSONSize != 0 {
maxBytes = t.MaxJSONSize
}
Expand All @@ -58,8 +59,8 @@ func (t *Tools) ReadJSON(w http.ResponseWriter, r *http.Request, data interface{
dec.DisallowUnknownFields()
}

// attempt to decode the data, and figure out what the error is, so as to send back a human readable
// response
// attempt to decode the data, and figure out what the error is, if any, to send back a human-readable
// response.
err := dec.Decode(data)
if err != nil {
var syntaxError *json.SyntaxError
Expand Down Expand Up @@ -373,3 +374,29 @@ func (t *Tools) WriteXML(w http.ResponseWriter, status int, data interface{}, he

return nil
}

// ReadXML tries to read the body of an XML request.
func (t *Tools) ReadXML(w http.ResponseWriter, r *http.Request, data interface{}) error {
maxBytes := 1024 * 1024 // one megabyte

// if MaxJSONSize is set, use that value instead of default
if t.MaxXMLSize != 0 {
maxBytes = t.MaxXMLSize
}
r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes))

dec := xml.NewDecoder(r.Body)

// attempt to decode the data
err := dec.Decode(data)
if err != nil {
return err
}

err = dec.Decode(&struct{}{})
if err != io.EOF {
return errors.New("body must only contain a single XML value")
}

return nil
}
55 changes: 48 additions & 7 deletions tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,33 +82,33 @@ func Test_ReadJSON(t *testing.T) {
// set max file size
testTools.MaxJSONSize = e.maxSize

// allow/disallow unknown fields
// allow/disallow unknown fields.
testTools.AllowUnknownFields = e.allowUnknown

// declare a variable to read the decoded json into
// declare a variable to read the decoded json into.
var decodedJSON struct {
Foo string `json:"foo"`
}

// create a request with the body
// create a request with the body.
req, err := http.NewRequest("POST", "/", bytes.NewReader([]byte(e.json)))
if err != nil {
t.Log("Error", err)
}

// create a test response recorder, which satisfies the requirements
// for a ResponseWriter
// for a ResponseWriter.
rr := httptest.NewRecorder()

// call readJSON and check for an error
// call ReadJSON and check for an error.
err = testTools.ReadJSON(rr, req, &decodedJSON)

// if we expect an error, but do not get one, something went wrong
// if we expect an error, but do not get one, something went wrong.
if e.errorExpected && err == nil {
t.Errorf("%s: error expected, but none received", e.name)
}

// if we do not expect an error, but get one, something went wrong
// if we do not expect an error, but get one, something went wrong.
if !e.errorExpected && err != nil {
t.Errorf("%s: error not expected, but one received: %s \n%s", e.name, err.Error(), e.json)
}
Expand Down Expand Up @@ -406,3 +406,44 @@ func TestTools_WriteXML(t *testing.T) {
t.Errorf("failed to write XML: %v", err)
}
}

func TestTools_ReadXML(t *testing.T) {
// create a variable of type toolbox.Tools, and just use the defaults.
var tools Tools

xmlPayload := `
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>John Smith</to>
<from>Jane Jones</from>
<heading>Reminder</heading>
<body>Buy some bread.</body>
</note>`

// create a request with the body
req, err := http.NewRequest("POST", "/", bytes.NewReader([]byte(xmlPayload)))
if err != nil {
t.Log("Error", err)
}

// create a test response recorder, which satisfies the requirements
// for a ResponseWriter
rr := httptest.NewRecorder()

// call ReadXML and check for an error.
var note struct {
To string `xml:"to"`
From string `xml:"from"`
Heading string `xml:"heading"`
Body string `xml:"body"`
}

err = tools.ReadXML(rr, req, &note)
if err != nil {
t.Error("error reading XML:", err)
}

if note.To != "John Smith" {
t.Errorf("wrong value in note; expected %s but got %s", "John Smith", note.To)
}
}

0 comments on commit f5707c1

Please sign in to comment.