A small, dependency-free Go library for parsing .http files — the request
format used by JetBrains IDEs and the VS Code REST Client
extension — into structured Go types.
httpparser is a pure parsing library. It does not execute requests and it
does not perform variable substitution: {{placeholder}} tokens are preserved
verbatim in URLs, header values, and bodies so that callers can resolve them
however they like. It depends only on the standard library.
go get github.com/uradical/httpparserRequires Go 1.21 or later.
package main
import (
"fmt"
"log"
"github.com/uradical/httpparser"
)
func main() {
f, err := httpparser.ParseFile("requests.http")
if err != nil {
log.Fatal(err)
}
for k, v := range f.Vars {
fmt.Printf("var %s = %s\n", k, v)
}
for _, req := range f.Requests {
fmt.Printf("%s %s %s (line %d)\n", req.Name, req.Method, req.URL, req.Line)
}
}Three entry points are provided, all returning a *File:
| Function | Input |
|---|---|
Parse(r io.Reader) |
any reader |
ParseFile(path string) |
a file on disk |
ParseString(s string) |
an in-memory string |
type File struct {
Vars map[string]string // file-level @key=value declarations
Requests []Request // requests in file order
}
type Request struct {
Name string // value of a "# @name <value>" annotation, or ""
Method string // upper-cased HTTP method
URL string // request target, placeholders left intact
Headers http.Header // request headers, values left intact
Body []byte // body trimmed of surrounding whitespace, or nil
Line int // 1-indexed line number of the "METHOD URL" line
}- Requests are written as
METHOD URL [HTTP-version]. The optional HTTP version is accepted and ignored. Supported methods areGET,POST,PUT,DELETE,PATCH,HEAD, andOPTIONS. - Multiple requests in one file are separated by a line beginning with
###. Any text after###(e.g.### create a user) is treated as a separator label and ignored. - Headers follow the request line as
Key: Valuepairs, up to the first blank line. - Body is everything after that blank line, trimmed of leading and trailing whitespace.
- File-level variables are declared with
@key = valuebefore the first request and collected intoFile.Vars. - Request names are set with a
# @name <value>(or// @name <value>) comment. The value may be separated by whitespace and/or=. - Comments begin with
#or//and are ignored (except for the@nameannotation).
@baseUrl = https://api.example.com
@token = abc123
# @name getUser
GET {{baseUrl}}/users/1 HTTP/1.1
Authorization: Bearer {{token}}
### create a user
# @name createUser
POST {{baseUrl}}/users
Content-Type: application/json
{
"name": "Ada",
"token": "{{token}}"
}Parsing this yields two requests (getUser and createUser) and two file-level
variables (baseUrl and token), with all {{...}} placeholders left
untouched.
Syntax errors are reported as a *ParseError, which carries the 1-indexed
Line, the offending Detail text, and a Kind that is one of the exported
sentinels — ErrMalformedRequestLine, ErrUnsupportedMethod, or
ErrMalformedHeader. Use errors.Is to check the kind and errors.As to read
the location:
f, err := httpparser.ParseString(src)
if err != nil {
var pe *httpparser.ParseError
if errors.As(err, &pe) {
log.Printf("syntax error on line %d: %v", pe.Line, pe.Kind)
}
if errors.Is(err, httpparser.ErrUnsupportedMethod) {
// handle an unsupported method specifically
}
}I/O errors from ParseFile (e.g. a missing file) are returned as-is and are
not *ParseError.
go test ./... # unit tests and examples