| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A Go port of unfetch — Jason Miller's tiny fetch polyfill.
The original is 500 bytes of JavaScript that implements just enough of the Fetch API to cover the common cases, on top of XMLHttpRequest. This port keeps that scope exactly: it does not grow the API, and it reproduces the original's behavior including the parts that are arguably bugs.
go get github.com/developit/unfetch-gores, err := unfetch.Fetch("/foo", nil)
if err != nil {
return err // transport failure only, never an HTTP error status
}
var data map[string]any
if err := res.JSON(&data); err != nil {
return err
}POST with headers and a body:
res, err := unfetch.Fetch("/foo", &unfetch.RequestInit{
Method: "post",
Headers: []unfetch.Header{{Name: "Content-Type", Value: "application/json"}},
Body: []byte(`{"a": "b"}`),
})Send cookies, the equivalent of credentials: 'include':
res, err := unfetch.Fetch("/foo", &unfetch.RequestInit{
Credentials: "include",
})Performs the request and blocks until it completes. A nil opts is equivalent to {} in JavaScript.
FetchAsync returns a *Promise instead, for code that wants the original's .then() / .catch() shape or needs to start several requests at once.
| Field | JS equivalent | Notes |
|---|---|---|
| Method string | options.method | Defaults to "get" |
| Headers []Header | options.headers | A slice, because request-header order is observable |
| Credentials string | options.credentials | Only the exact string "include" enables cookies |
| Body []byte | options.body | Empty or nil sends no request entity |
HeadersFromMap converts a map[string]string using JavaScript's own for...in property order (integer-like keys ascending, then insertion order — which for a Go map is unrecoverable, so lexicographic is used as the stable stand-in). Prefer building the slice directly when order matters.
| Member | JS equivalent |
|---|---|
| OK bool | res.ok |
| Status int | res.status |
| StatusText string | res.statusText |
| URL string | res.url — the URL after redirects |
| Headers *Headers | res.headers |
| Text() (string, error) | res.text() |
| JSON(v any) error | res.json() |
| JSONRaw() (any, error) | res.json() into an untyped value |
| Blob() (*Blob, error) | res.blob() |
| Clone() *Response | res.clone() |
Only the four members the original implements: Keys(), Entries(), Get(name), Has(name). Header names are always lowercase. There is no Append, Set, Delete, or iteration — the original types those as never, and so does this port.
These are inherited from upstream by design.
Cookies are not sent by default. Set Credentials: "include". Note that only that exact string works; "same-origin" behaves like "omit", matching the original's options.credentials == "include" check.
An HTTP error status is not an error. A 404 or 500 returns a *Response with OK == false and a nil error. Only a transport failure returns an error, and it is always a *NetworkError. Check res.OK.
OK uses truncating division. ok is status/100 == 2, so any status from 200 to 299 is ok — and so is a nonsensical status like 2 or 29, exactly as in the original.
The equivalent of polyfill/polyfill.mjs (if (!self.fetch) self.fetch = unfetch). Install() registers Fetch only when no implementation is present, and reports whether it did. On js/wasm it installs a real, JS-callable globalThis.fetch.
The equivalent of the isomorphic-unfetch package: Resolve picks node-fetch-style behavior when a process-like environment is detected and plain unfetch otherwise, while ResolveBrowser always picks unfetch. The node branch rewrites protocol-relative //host URLs to https://host, as upstream does.
Fetch talks to an XHR interface rather than to net/http directly, mirroring the original's dependency on XMLHttpRequest. This is also the seam the tests use, in place of upstream's jest.fn() mock.
Swap in your own with SetXHRFactory, or pass one per call to FetchWithXHR.
Documented in full in MIGRATION.md. The short version: the API surface and observable behavior match; what changes is the shape imposed by Go's type system (JSON needs a destination, Get returns a second ok value, headers are an ordered slice) plus the addition of a blocking Fetch alongside the promise-based FetchAsync.
MIT © Jason Miller, as the original.
| Back | FazBrowse Home | New Git URL |