* Bump the go-modules-updates group in /backend with 7 updates Bumps the go-modules-updates group in /backend with 7 updates: | Package | From | To | | --- | --- | --- | | [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) | `2.21.1` | `2.23.1` | | [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) | `5.2.3` | `5.2.4` | | [github.com/go-pkgz/rest](https://github.com/go-pkgz/rest) | `1.20.6` | `1.21.0` | | [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) | `5.3.0` | `5.3.1` | | [golang.org/x/crypto](https://github.com/golang/crypto) | `0.46.0` | `0.47.0` | | [golang.org/x/image](https://github.com/golang/image) | `0.34.0` | `0.35.0` | | [golang.org/x/net](https://github.com/golang/net) | `0.48.0` | `0.49.0` | Updates `github.com/alecthomas/chroma/v2` from 2.21.1 to 2.23.1 - [Release notes](https://github.com/alecthomas/chroma/releases) - [Commits](https://github.com/alecthomas/chroma/compare/v2.21.1...v2.23.1) Updates `github.com/go-chi/chi/v5` from 5.2.3 to 5.2.4 - [Release notes](https://github.com/go-chi/chi/releases) - [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md) - [Commits](https://github.com/go-chi/chi/compare/v5.2.3...v5.2.4) Updates `github.com/go-pkgz/rest` from 1.20.6 to 1.21.0 - [Release notes](https://github.com/go-pkgz/rest/releases) - [Commits](https://github.com/go-pkgz/rest/compare/v1.20.6...v1.21.0) Updates `github.com/golang-jwt/jwt/v5` from 5.3.0 to 5.3.1 - [Release notes](https://github.com/golang-jwt/jwt/releases) - [Commits](https://github.com/golang-jwt/jwt/compare/v5.3.0...v5.3.1) Updates `golang.org/x/crypto` from 0.46.0 to 0.47.0 - [Commits](https://github.com/golang/crypto/compare/v0.46.0...v0.47.0) Updates `golang.org/x/image` from 0.34.0 to 0.35.0 - [Commits](https://github.com/golang/image/compare/v0.34.0...v0.35.0) Updates `golang.org/x/net` from 0.48.0 to 0.49.0 - [Commits](https://github.com/golang/net/compare/v0.48.0...v0.49.0) --- updated-dependencies: - dependency-name: github.com/alecthomas/chroma/v2 dependency-version: 2.23.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: github.com/go-chi/chi/v5 dependency-version: 5.2.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-modules-updates - dependency-name: github.com/go-pkgz/rest dependency-version: 1.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: github.com/golang-jwt/jwt/v5 dependency-version: 5.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-modules-updates - dependency-name: golang.org/x/crypto dependency-version: 0.47.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: golang.org/x/image dependency-version: 0.35.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: golang.org/x/net dependency-version: 0.49.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates ... Signed-off-by: dependabot[bot] <support@github.com> * Run go mod tidy in examples directory Co-authored-by: paskal <712534+paskal@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: paskal <712534+paskal@users.noreply.github.com>
117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
// Package rest provides common middlewares and helpers for rest services
|
|
package rest
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// JSON is a map alias, just for convenience
|
|
type JSON map[string]any
|
|
|
|
// RenderJSON sends data as json
|
|
func RenderJSON(w http.ResponseWriter, data any) {
|
|
buf := &bytes.Buffer{}
|
|
enc := json.NewEncoder(buf)
|
|
enc.SetEscapeHTML(true)
|
|
if err := enc.Encode(data); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_, _ = w.Write(buf.Bytes())
|
|
}
|
|
|
|
// RenderJSONFromBytes sends binary data as json
|
|
func RenderJSONFromBytes(w http.ResponseWriter, r *http.Request, data []byte) error {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
if _, err := w.Write(data); err != nil {
|
|
return fmt.Errorf("failed to send response to %s: %w", r.RemoteAddr, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RenderJSONWithHTML allows html tags and forces charset=utf-8
|
|
func RenderJSONWithHTML(w http.ResponseWriter, r *http.Request, v any) error {
|
|
encodeJSONWithHTML := func(v any) ([]byte, error) {
|
|
buf := &bytes.Buffer{}
|
|
enc := json.NewEncoder(buf)
|
|
enc.SetEscapeHTML(false)
|
|
if err := enc.Encode(v); err != nil {
|
|
return nil, fmt.Errorf("json encoding failed: %w", err)
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
data, err := encodeJSONWithHTML(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return RenderJSONFromBytes(w, r, data)
|
|
}
|
|
|
|
// renderJSONWithStatus sends data as json and enforces status code
|
|
func renderJSONWithStatus(w http.ResponseWriter, data any, code int) {
|
|
buf := &bytes.Buffer{}
|
|
enc := json.NewEncoder(buf)
|
|
enc.SetEscapeHTML(true)
|
|
if err := enc.Encode(data); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(code)
|
|
_, _ = w.Write(buf.Bytes())
|
|
}
|
|
|
|
// ParseFromTo parses from and to query params of the request
|
|
func ParseFromTo(r *http.Request) (from, to time.Time, err error) {
|
|
parseTimeStamp := func(ts string) (time.Time, error) {
|
|
formats := []string{
|
|
"2006-01-02T15:04:05.000000000",
|
|
"2006-01-02T15:04:05",
|
|
"2006-01-02T15:04",
|
|
"20060102",
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
}
|
|
|
|
for _, f := range formats {
|
|
if t, e := time.Parse(f, ts); e == nil {
|
|
return t, nil
|
|
}
|
|
}
|
|
return time.Time{}, fmt.Errorf("can't parse date %q", ts)
|
|
}
|
|
|
|
if from, err = parseTimeStamp(r.URL.Query().Get("from")); err != nil {
|
|
return from, to, fmt.Errorf("incorrect from time: %w", err)
|
|
}
|
|
|
|
if to, err = parseTimeStamp(r.URL.Query().Get("to")); err != nil {
|
|
return from, to, fmt.Errorf("incorrect to time: %w", err)
|
|
}
|
|
return from, to, nil
|
|
}
|
|
|
|
// DecodeJSON decodes json request from http.Request to given type
|
|
func DecodeJSON[T any](r *http.Request, res *T) error {
|
|
if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
|
|
return fmt.Errorf("decode json: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// EncodeJSON encodes given type to http.ResponseWriter and sets status code and content type header
|
|
func EncodeJSON[T any](w http.ResponseWriter, status int, v T) error {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(status)
|
|
if err := json.NewEncoder(w).Encode(v); err != nil {
|
|
return fmt.Errorf("encode json: %w", err)
|
|
}
|
|
return nil
|
|
}
|