https://github.com/ezartsh/inrequest
Go package for parsing HTTP request bodies (form-data, JSON, query params) into maps and structs with automatic type conversion and file upload support.
https://github.com/ezartsh/inrequest
file-upload form-data go golang http json multipart parser request-parser struct-binding
Last synced: 1 day ago
JSON representation
Go package for parsing HTTP request bodies (form-data, JSON, query params) into maps and structs with automatic type conversion and file upload support.
- Host: GitHub
- URL: https://github.com/ezartsh/inrequest
- Owner: ezartsh
- License: mit
- Created: 2023-08-25T05:19:44.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2025-12-05T09:14:08.000Z (3 months ago)
- Last Synced: 2025-12-08T18:08:35.212Z (3 months ago)
- Topics: file-upload, form-data, go, golang, http, json, multipart, parser, request-parser, struct-binding
- Language: Go
- Homepage: https://pkg.go.dev/github.com/ezartsh/inrequest
- Size: 44.9 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Go Inrequest
[](https://go.dev/)
[](LICENSE)
[](https://goreportcard.com/report/github.com/ezartsh/inrequest)
**Golang package for transforming HTTP request body into Go maps and structs.**
Supports multiple content types:
- `multipart/form-data` (with file uploads)
- `application/x-www-form-urlencoded`
- `application/json`
- Query string parameters
---
## Installation
Requires [Go](https://go.dev/) 1.17+
```sh
go get github.com/ezartsh/inrequest
```
## Import
```go
import "github.com/ezartsh/inrequest"
```
---
## Quick Start
```go
package main
import (
"fmt"
"net/http"
"github.com/ezartsh/inrequest"
)
func main() {
http.HandleFunc("/submit", func(w http.ResponseWriter, r *http.Request) {
// Parse form data
req := inrequest.FormData(r)
defer req.Cleanup() // Optional: clean up temp files
fmt.Println(req.ToMap())
// output: map[first_name:John last_name:Smith]
})
http.ListenAndServe(":8080", nil)
}
```
---
## API Reference
### Entry Functions
| Function | Description |
|----------|-------------|
| `FormData(r *http.Request)` | Parse multipart/form-data or url-encoded form |
| `FormDataWithOptions(r *http.Request, opts Options)` | Parse form with custom options |
| `Query(r *http.Request)` | Parse query string parameters |
| `Json(r *http.Request)` | Parse JSON request body |
| `Parse(r *http.Request)` | Auto-detect and parse based on Content-Type |
### Options
```go
type Options struct {
MaxMemory int64 // Max memory for multipart parsing (default: 32MB)
}
```
### Request Interface
All request types implement the `Request` interface:
```go
type Request interface {
ToMap() RequestValue // Get as map[string]interface{}
ToBind(model interface{}) error // Bind to struct
ToJsonByte() ([]byte, error) // Get as JSON bytes
ToJsonString() (string, error) // Get as JSON string
}
```
### FormRequest Additional Methods
```go
// Cleanup removes temporary files created during multipart form parsing.
// Optional but recommended for high-traffic servers.
func (r FormRequest) Cleanup()
```
### Types
```go
// RequestValue is the parsed request data
type RequestValue = map[string]interface{}
// FileHeaders represents multiple uploaded files for a single field
type FileHeaders []*multipart.FileHeader
```
---
## Request Body Types
- [Form Data](#1-form-data)
- [Query String](#2-query-string)
- [JSON Request](#3-json-request)
- [Auto Parse](#4-auto-parse)
---
## 1. Form Data
### Basic Example
```html
```
```go
package main
import (
"fmt"
"net/http"
"github.com/ezartsh/inrequest"
)
type BodyRequest struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
func main() {
http.HandleFunc("/submit", func(w http.ResponseWriter, r *http.Request) {
req := inrequest.FormData(r)
defer req.Cleanup()
// Get as map
fmt.Println(req.ToMap())
// output: map[first_name:John last_name:Smith]
// Bind to struct
var body BodyRequest
req.ToBind(&body)
fmt.Printf("My name is %s %s\n", body.FirstName, body.LastName)
// output: My name is John Smith
// Get as JSON string
if jsonStr, err := req.ToJsonString(); err == nil {
fmt.Println(jsonStr)
// output: {"first_name":"John","last_name":"Smith"}
}
})
http.ListenAndServe(":8080", nil)
}
```
### Nested Arrays and Objects
```html
Description 1
Description 2
```
```go
req := inrequest.FormData(r)
defer req.Cleanup()
jsonStr, _ := req.ToJsonString()
fmt.Println(jsonStr)
```
**Output:**
```json
{
"names": ["John", "Smith", "Doe"],
"attachments": [
{
"title": "Title 1",
"description": "Description 1",
"file": {
"Filename": "document.pdf",
"Header": {
"Content-Type": ["application/pdf"]
},
"Size": 13264
}
},
{
"title": "Title 2",
"description": "Description 2",
"file": {
"Filename": "image.png",
"Header": {
"Content-Type": ["image/png"]
},
"Size": 8192
}
}
]
}
```
### Multiple File Uploads
For multiple files with the same field name, use `FileHeaders`:
```html
```
```go
type UploadRequest struct {
Documents inrequest.FileHeaders `json:"documents"`
}
req := inrequest.FormData(r)
defer req.Cleanup()
var upload UploadRequest
req.ToBind(&upload)
for _, file := range upload.Documents {
fmt.Printf("File: %s, Size: %d\n", file.Filename, file.Size)
}
```
### Custom Memory Limit
```go
req := inrequest.FormDataWithOptions(r, inrequest.Options{
MaxMemory: 10 << 20, // 10 MB
})
defer req.Cleanup()
```
---
## 2. Query String
```
GET /search?utm_source=google&callback_url=http://localhost:3000&status=active
```
```go
package main
import (
"fmt"
"net/http"
"github.com/ezartsh/inrequest"
)
func main() {
http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
req := inrequest.Query(r)
fmt.Println(req.ToMap())
// output: map[callback_url:http://localhost:3000 status:active utm_source:google]
if jsonStr, err := req.ToJsonString(); err == nil {
fmt.Println(jsonStr)
// output: {"callback_url":"http://localhost:3000","status":"active","utm_source":"google"}
}
})
http.ListenAndServe(":8080", nil)
}
```
### Nested Query Parameters
```
GET /filter?filters[status]=active&filters[category]=tech&items[0]=a&items[1]=b
```
```go
req := inrequest.Query(r)
fmt.Println(req.ToMap())
// output: map[filters:map[status:active category:tech] items:[a b]]
```
---
## 3. JSON Request
```json
{
"first_name": "John",
"last_name": "Smith",
"age": 31
}
```
```go
package main
import (
"fmt"
"net/http"
"github.com/ezartsh/inrequest"
)
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age"`
}
func main() {
http.HandleFunc("/api/person", func(w http.ResponseWriter, r *http.Request) {
req := inrequest.Json(r)
fmt.Println(req.ToMap())
// output: map[age:31 first_name:John last_name:Smith]
var person Person
req.ToBind(&person)
fmt.Printf("%s is %d years old\n", person.FirstName, person.Age)
// output: John is 31 years old
if jsonStr, err := req.ToJsonString(); err == nil {
fmt.Println(jsonStr)
// output: {"age":31,"first_name":"John","last_name":"Smith"}
}
})
http.ListenAndServe(":8080", nil)
}
```
---
## 4. Auto Parse
Use `Parse()` to automatically detect and parse based on `Content-Type`:
```go
http.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
req := inrequest.Parse(r)
// Works with any content type:
// - application/json
// - multipart/form-data
// - application/x-www-form-urlencoded
// - Falls back to query string
fmt.Println(req.ToMap())
})
```
---
## Type Conversion
The library automatically converts string values to appropriate Go types:
| Input | Output Type |
|-------|-------------|
| `"123"` | `int` |
| `"3.14"` | `float64` |
| `"true"`, `"false"` | `bool` |
| `"null"` | `nil` |
| Other strings | `string` |
---
## Binding to Structs
Use `ToBind()` to bind request data to a struct. The struct fields should have `json` tags:
```go
type CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
Active bool `json:"active"`
Avatar *multipart.FileHeader `json:"avatar"` // Single file
Photos inrequest.FileHeaders `json:"photos"` // Multiple files
}
req := inrequest.FormData(r)
defer req.Cleanup()
var user CreateUserRequest
if err := req.ToBind(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Access file
if user.Avatar != nil {
fmt.Printf("Avatar: %s\n", user.Avatar.Filename)
}
// Access multiple files
for _, photo := range user.Photos {
fmt.Printf("Photo: %s\n", photo.Filename)
}
```
---
## Performance
The library is optimized for performance:
| Operation | Time |
|-----------|------|
| Simple form (5 fields) | ~5 µs |
| Complex nested form | ~50 µs |
| Large form (100 fields) | ~200 µs |
| File upload | ~500 µs |
Memory allocation is minimal, and temporary files are cleaned up with `Cleanup()`.
---
## Contributing
If you have a bug report or feature request, you can [open an issue](https://github.com/ezartsh/inrequest/issues/new), and [pull requests](https://github.com/ezartsh/inrequest/pulls) are also welcome.
## License
`inrequest` is released under the MIT license. See [LICENSE](LICENSE) for details.