Skip to content

Commit

Permalink
Merge pull request #4 from syntaqx/master
Browse files Browse the repository at this point in the history
Add ContentTypeForm functionality to DecodeForm
  • Loading branch information
VojtechVitek committed Apr 29, 2021
2 parents 3215478 + d098851 commit 996350f
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 32 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/golangci-lint.yml
@@ -0,0 +1,19 @@
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.29
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
@@ -0,0 +1,24 @@
name: test
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- run: go mod download
- name: Run tests
run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
vendor
15 changes: 0 additions & 15 deletions .travis.yml

This file was deleted.

5 changes: 4 additions & 1 deletion README.md
@@ -1,5 +1,9 @@
# render

![tests](https://github.com/go-chi/render/actions/workflows/test.yml/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-chi/render)](https://goreportcard.com/report/github.com/go-chi/render)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-chi/render.svg)](https://pkg.go.dev/github.com/go-chi/render)

The `render` package helps manage HTTP request / response payloads.

Every well-designed, robust and maintainable Web Service / REST API also needs
Expand All @@ -21,4 +25,3 @@ request bodies. Please have a look at the [rest](https://github.com/go-chi/chi/b
example which uses the latest chi/render sub-pkg.

All feedback is welcome, thank you!

19 changes: 16 additions & 3 deletions decoder.go
Expand Up @@ -7,6 +7,8 @@ import (
"io"
"io/ioutil"
"net/http"

"github.com/ajg/form"
)

// Decode is a package-level variable set to our default Decoder. We do this
Expand All @@ -17,6 +19,8 @@ import (
// bytes allowed to be read from the request body.
var Decode = DefaultDecoder

// DefaultDecoder detects the correct decoder for use on an HTTP request and
// marshals into a given interface.
func DefaultDecoder(r *http.Request, v interface{}) error {
var err error

Expand All @@ -25,20 +29,29 @@ func DefaultDecoder(r *http.Request, v interface{}) error {
err = DecodeJSON(r.Body, v)
case ContentTypeXML:
err = DecodeXML(r.Body, v)
// case ContentTypeForm: // TODO
case ContentTypeForm:
err = DecodeForm(r.Body, v)
default:
err = errors.New("render: unable to automatically decode the request content type")
}

return err
}

// DecodeJSON decodes a given reader into an interface using the json decoder.
func DecodeJSON(r io.Reader, v interface{}) error {
defer io.Copy(ioutil.Discard, r)
defer io.Copy(ioutil.Discard, r) //nolint:errcheck
return json.NewDecoder(r).Decode(v)
}

// DecodeXML decodes a given reader into an interface using the xml decoder.
func DecodeXML(r io.Reader, v interface{}) error {
defer io.Copy(ioutil.Discard, r)
defer io.Copy(ioutil.Discard, r) //nolint:errcheck
return xml.NewDecoder(r).Decode(v)
}

// DecodeForm decodes a given reader into an interface using the form decoder.
func DecodeForm(r io.Reader, v interface{}) error {
decoder := form.NewDecoder(r) //nolint:errcheck
return decoder.Decode(v)
}
5 changes: 5 additions & 0 deletions go.mod
@@ -0,0 +1,5 @@
module github.com/go-chi/render

go 1.16

require github.com/ajg/form v1.5.1
2 changes: 2 additions & 0 deletions go.sum
@@ -0,0 +1,2 @@
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
26 changes: 13 additions & 13 deletions responder.go
Expand Up @@ -66,7 +66,7 @@ func PlainText(w http.ResponseWriter, r *http.Request, v string) {
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write([]byte(v))
w.Write([]byte(v)) //nolint:errcheck
}

// Data writes raw bytes to the response, setting the Content-Type as
Expand All @@ -76,7 +76,7 @@ func Data(w http.ResponseWriter, r *http.Request, v []byte) {
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write(v)
w.Write(v) //nolint:errcheck
}

// HTML writes a string to the response, setting the Content-Type as text/html.
Expand All @@ -85,7 +85,7 @@ func HTML(w http.ResponseWriter, r *http.Request, v string) {
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write([]byte(v))
w.Write([]byte(v)) //nolint:errcheck
}

// JSON marshals 'v' to JSON, automatically escaping HTML and setting the
Expand All @@ -103,7 +103,7 @@ func JSON(w http.ResponseWriter, r *http.Request, v interface{}) {
if status, ok := r.Context().Value(StatusCtxKey).(int); ok {
w.WriteHeader(status)
}
w.Write(buf.Bytes())
w.Write(buf.Bytes()) //nolint:errcheck
}

// XML marshals 'v' to JSON, setting the Content-Type as application/xml. It
Expand All @@ -128,15 +128,15 @@ func XML(w http.ResponseWriter, r *http.Request, v interface{}) {
}
if !bytes.Contains(b[:findHeaderUntil], []byte("<?xml")) {
// No header found. Print it out first.
w.Write([]byte(xml.Header))
w.Write([]byte(xml.Header)) //nolint:errcheck
}

w.Write(b)
w.Write(b) //nolint:errcheck
}

// NoContent returns a HTTP 204 "No Content" response.
func NoContent(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(204)
w.WriteHeader(http.StatusNoContent)
}

func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) {
Expand All @@ -153,7 +153,7 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) {
w.Header().Set("Connection", "keep-alive")
}

w.WriteHeader(200)
w.WriteHeader(http.StatusOK)

ctx := r.Context()
for {
Expand All @@ -162,12 +162,12 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) {
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(v)},
}); chosen {
case 0: // equivalent to: case <-ctx.Done()
w.Write([]byte("event: error\ndata: {\"error\":\"Server Timeout\"}\n\n"))
w.Write([]byte("event: error\ndata: {\"error\":\"Server Timeout\"}\n\n")) //nolint:errcheck
return

default: // equivalent to: case v, ok := <-stream
if !ok {
w.Write([]byte("event: EOF\n\n"))
w.Write([]byte("event: EOF\n\n")) //nolint:errcheck
return
}
v := recv.Interface()
Expand All @@ -184,13 +184,13 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) {

bytes, err := json.Marshal(v)
if err != nil {
w.Write([]byte(fmt.Sprintf("event: error\ndata: {\"error\":\"%v\"}\n\n", err)))
w.Write([]byte(fmt.Sprintf("event: error\ndata: {\"error\":\"%v\"}\n\n", err))) //nolint:errcheck
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
continue
}
w.Write([]byte(fmt.Sprintf("event: data\ndata: %s\n\n", bytes)))
w.Write([]byte(fmt.Sprintf("event: data\ndata: %s\n\n", bytes))) //nolint:errcheck
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
Expand All @@ -209,7 +209,7 @@ func channelIntoSlice(w http.ResponseWriter, r *http.Request, from interface{})
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(from)},
}); chosen {
case 0: // equivalent to: case <-ctx.Done()
http.Error(w, "Server Timeout", 504)
http.Error(w, "Server Timeout", http.StatusGatewayTimeout)
return nil

default: // equivalent to: case v, ok := <-stream
Expand Down

0 comments on commit 996350f

Please sign in to comment.