jsonxmltool

package module
v0.0.0-...-c06c9c3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 15 Imported by: 0

README

Version Built with Go License Go Report Card Tests pkg.go.dev reference Coverage

GO HTTP JSON/XML -AND- FILE LIBRARY

A Go module of HTTP helpers focused on JSON, XML, multipart uploads, and small web utilities. Use it in handlers and services when you want consistent envelopes, body limits, and clearer decode errors without pulling in a full framework.

This is a utility package, not a web framework. It does not provide routing, middleware stacks, auth, validation libraries, or OpenAPI tooling.

When to use

  • You build APIs with net/http (or a thin router) and want shared handler patterns.
  • You want body size limits, stricter JSON parsing (unknown fields, single document), and human-readable decode errors without copying that logic into every handler.
  • You want consistent JSON/XML response shapes (JSONEnvelope, XMLEnvelope) across endpoints.
  • You need small, related helpers in the same style: multipart uploads, attachment downloads, URL slugs, outbound JSON POSTs.

The JSON handler example below is most valuable when you have many endpoints repeating the same read <> validate <> respond flow. For a single trivial handler, the standard library alone is often enough.

When not to use

  • You already use Gin, Echo, Fiber, Chi with binding, or similar and get request parsing, limits, and errors from that stack.
  • You need a full framework (routing, DI, migrations, generated API docs).
  • Your service is not HTTP-facing, or only needs one-off json.Marshal / json.Unmarshal with no shared conventions.

Install

go get github.com/dunky-star/go-json-xml-tool

Quick start

package main

import (
	"fmt"

	"github.com/dunky-star/go-json-xml-tool"
)

func main() {
	k := jsonxmltool.NewKit()
	fmt.Println(k.RandomString(16))
}

Encoding model

Reads use json.Decoder / xml.Decoder on the request body (streaming, size-limited).
Writes use json.Encoder / xml.Encoder on the response or buffer — not Marshal — so large payloads are not held entirely in memory before send.

What’s included

Area Methods
JSON ReadJSON, WriteJSON, ErrorJSON, PostJSON
XML ReadXML, WriteXML, ErrorXML
Uploads ReceiveUploads, ReceiveOneUpload
Files ServeAttachment, EnsureDir
Text URLSlug, RandomString

Configure limits and MIME allowlists on Kit:

k := jsonxmltool.NewKit()
k.MaxJSONSize = 1 << 20
k.AllowedFileTypes = []string{"image/png", "image/jpeg"}

JSON handler example

type createInput struct {
	Name string `json:"name"`
}

func create(w http.ResponseWriter, r *http.Request) {
	k := jsonxmltool.NewKit()
	var in createInput
	if err := k.ReadJSON(w, r, &in); err != nil {
		_ = k.ErrorJSON(w, err)
		return
	}
	_ = k.WriteJSON(w, http.StatusCreated, jsonxmltool.JSONEnvelope{
		Error: false, Message: "created", Data: in.Name,
	})
}

Multipart upload example

Client form (any field name; multiple is optional):

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="file" multiple />
  <button type="submit">Upload</button>
</form>

Handler:

func upload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}

	k := jsonxmltool.Kit{
		MaxFileSize:      10 << 20, // 10 MiB
		AllowedFileTypes: []string{"image/png", "image/jpeg"},
	}

	// ReceiveUploads creates uploadDir if needed and assigns random on-disk names by default.
	// Pass false as the third argument to keep original filenames: ReceiveUploads(r, "./uploads", false)
	files, err := k.ReceiveUploads(r, "./uploads")
	if err != nil {
		_ = k.ErrorJSON(w, err)
		return
	}

	_ = k.WriteJSON(w, http.StatusOK, jsonxmltool.JSONEnvelope{
		Error:   false,
		Message: "uploaded",
		Data:    files, // []*jsonxmltool.StoredFile (saved name, original name, size)
	})
}

// Single file only:
func uploadOne(w http.ResponseWriter, r *http.Request) {
	k := jsonxmltool.NewKit()
	file, err := k.ReceiveOneUpload(r, "./uploads")
	if err != nil {
		_ = k.ErrorJSON(w, err)
		return
	}
	_ = k.WriteJSON(w, http.StatusOK, jsonxmltool.JSONEnvelope{Data: file})
}

ReceiveUploads checks each file’s size against MaxFileSize, sniffs MIME type (first 512 bytes), and rejects types not listed in AllowedFileTypes (empty list allows any detected type).

XML handler example

import (
	"encoding/xml"
	"net/http"

	"github.com/dunky-star/go-json-xml-tool"
)

type ping struct {
	XMLName xml.Name `xml:"ping"`
	Text    string   `xml:",chardata"`
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
	k := jsonxmltool.NewKit()
	var body ping
	if err := k.ReadXML(w, r, &body); err != nil {
		_ = k.ErrorXML(w, err)
		return
	}
	_ = k.WriteXML(w, http.StatusOK, jsonxmltool.XMLEnvelope{Message: "pong"})
}

Development

go test ./...
go vet ./...

Documentation

Overview

Package jsonxmltool provides HTTP-oriented helpers for JSON, XML, uploads, and small web utilities.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type JSONEnvelope

type JSONEnvelope struct {
	Error   bool   `json:"error"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

JSONEnvelope is a conventional JSON API wrapper with optional data.

type Kit

type Kit struct {
	MaxJSONSize        int         // cap on JSON request bodies; zero uses defaultBodyLimit
	MaxXMLSize         int         // cap on XML request bodies; zero uses defaultBodyLimit
	MaxFileSize        int         // cap per uploaded file in bytes; zero uses defaultBodyLimit
	AllowedFileTypes   []string    // MIME types allowed for uploads (e.g. image/png); empty allows any detected type
	AllowUnknownFields bool        // when false, json.Decoder rejects keys not present on the target struct
	ErrorLog           *log.Logger // diagnostics for failures
	InfoLog            *log.Logger // routine operational messages
}

Kit groups configurable limits and loggers for the helper methods below. Construct one with NewKit and call methods on a pointer when you need to mutate limits in place.

func NewKit

func NewKit() Kit

NewKit returns a Kit with 10 MiB limits and stdout loggers.

func (*Kit) EnsureDir

func (k *Kit) EnsureDir(path string) error

EnsureDir creates path and any missing parents with mode 0755.

func (*Kit) ErrorJSON

func (k *Kit) ErrorJSON(w http.ResponseWriter, err error, status ...int) error

ErrorJSON sends a JSONEnvelope with Error set and Message from err.

func (*Kit) ErrorXML

func (k *Kit) ErrorXML(w http.ResponseWriter, err error, status ...int) error

ErrorXML sends an XMLEnvelope with Error set and Message from err.

func (*Kit) PostJSON

func (k *Kit) PostJSON(uri string, data any, client ...*http.Client) (*http.Response, int, error)

PostJSON encodes data with json.Encoder into the POST body. An optional client overrides http.DefaultClient.

func (*Kit) RandomString

func (k *Kit) RandomString(n int) string

RandomString returns a string of length n drawn from tokenAlphabet.

func (*Kit) ReadJSON

func (k *Kit) ReadJSON(w http.ResponseWriter, r *http.Request, data any) error

ReadJSON decodes a single JSON value from r.Body into data (must be a pointer). When Content-Type is set, it must be application/json (case-insensitive).

func (*Kit) ReadXML

func (k *Kit) ReadXML(w http.ResponseWriter, r *http.Request, data any) error

ReadXML decodes a single XML document from r.Body into data (must be a pointer).

func (*Kit) ReceiveOneUpload

func (k *Kit) ReceiveOneUpload(r *http.Request, uploadDir string, rename ...bool) (*StoredFile, error)

ReceiveOneUpload saves the first file in a multipart request to uploadDir.

func (*Kit) ReceiveUploads

func (k *Kit) ReceiveUploads(r *http.Request, uploadDir string, rename ...bool) ([]*StoredFile, error)

ReceiveUploads stores multipart files under uploadDir, optionally replacing names with random tokens.

func (*Kit) ServeAttachment

func (k *Kit) ServeAttachment(w http.ResponseWriter, r *http.Request, dir, name, displayName string)

ServeAttachment streams a file from dir/name as a download using displayName in Content-Disposition.

func (*Kit) URLSlug

func (k *Kit) URLSlug(s string) (string, error)

URLSlug lowercases s, replaces non-alphanumeric runs with hyphens, and trims edges.

func (*Kit) WriteJSON

func (k *Kit) WriteJSON(w http.ResponseWriter, status int, data any, headers ...http.Header) error

WriteJSON streams data as JSON via json.Encoder (no full-buffer Marshal). Optional headers merge into the response before the body is sent.

func (*Kit) WriteXML

func (k *Kit) WriteXML(w http.ResponseWriter, status int, data any, headers ...http.Header) error

WriteXML streams data with xml.Encoder after the standard XML declaration.

type StoredFile

type StoredFile struct {
	NewFileName      string
	OriginalFileName string
	FileSize         int64
}

StoredFile records how an upload was persisted on disk.

type XMLEnvelope

type XMLEnvelope struct {
	Error   bool   `xml:"error"`
	Message string `xml:"message"`
	Data    any    `xml:"data,omitempty"`
}

XMLEnvelope mirrors JSONEnvelope for XML responses.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL