Skip to content

v1.6.0

Choose a tag to compare

@github-actions github-actions released this 05 Sep 09:46
· 124 commits to main since this release

Kurlo 1.6.0

Added

  • Import an OpenAPI or Swagger spec from a URL. Every import path took a file, so bringing in a spec meant downloading it first — and a spec URL is what teams actually pass around, because it is the one that stays current. Import collection → OpenAPI / Swagger from URL takes the link, fetches it, and builds the same collection the file import would: {{baseUrl}} as a collection variable, path parameters seeded from the spec, declared security schemes mapped onto each request's auth. The fetch goes through the Go sender rather than the WebView — a spec host has no reason to send CORS headers, and it brings redirect following, the proxy settings a corporate network needs, and the response cap. A link with no scheme is read as https, cookies are left out of the request, and the collection is named from the spec's info.title, falling back to the host rather than to a generic path segment like /v3/api-docs.
  • A URL that turns out not to be a spec says which of the several things went wrong, in a dialog rather than a toast that has gone by the time it is read. The one worth naming: pasting the Swagger UI page rather than the document it renders is the most common mistake by far, and "could not parse" would send someone looking at the wrong end of it — so that case says so, and names where the document usually lives.

Fixed

  • An upload went out with no Content-Length. net/http works the body length out for itself only for the in-memory reader types, so a binary file body and a multipart body — both streams — were framed Transfer-Encoding: chunked. That is exactly what the services people upload to refuse: an S3 presigned PUT requires a declared length, so does Azure Blob, and a fair number of nginx and API-gateway setups answer 411 Length Required and nothing else. Both now declare their exact size. The multipart length is computed from the rows without writing anything, and a test measures a real body against that arithmetic so the assumption it makes about mime/multipart's framing cannot drift silently; a file that cannot be measured leaves the length unknown and streams chunked as before. The same gap left GetBody empty, so a 307/308 redirect had nothing to replay and abandoned the send — a file body now survives one.
  • The Auth tab silently replaced a header written by hand. Auth is applied after the header rows, so configuring bearer auth and typing an Authorization header sent the tab's value and discarded the row — with the row still on screen, looking sent. The precedence is unchanged (it is the safe one to keep), but the response panel now names what was replaced, next to the notice that already explains dropped framing headers. Covers Authorization for bearer, Basic and OAuth 2.0, and whatever header name an API key is configured under.
  • AWS Signature v4 signed the path with one URI encoding. S3 wants exactly that, but every other service asks for the path to be normalised per RFC 3986 and then encoded twice. Any path carrying a character that needs escaping was therefore rejected with SignatureDoesNotMatch — including the ordinary shape of a Lambda invoke URL, which carries the function ARN, colons and all, in the path. S3 keeps its own rule.
  • A form part's Content-Type was lost when a cURL command was pasted. The parser has read curl's ;type= suffix since 1.5.0 and the export writes it, but the paste path dropped it while building the rows — the one place that round trip was broken, and the difference between an upload an API accepts and one it rejects on the MIME type.
  • Copying a request as cURL or as a code snippet mislabelled the body. Only JSON and GraphQL bodies got a Content-Type, so an XML, HTML or plain-text body arrived as curl's own default, application/x-www-form-urlencoded — a different request from the one that was copied. Every string-payload body type now declares what the sender declares, taken from one table shared by both generators. The body also goes out as --data-raw, since -d reads a leading @ as a filename.
  • -k, --max-time and --proxy were discarded when a cURL command was pasted. Each maps onto a request setting Kurlo already has, so the pasted command produced a request that quietly behaved differently — most of all -k, whose entire purpose is that the endpoint's certificate does not verify.
  • A second value for a query parameter already in the URL was dropped. Folding the URL's query into the params table deduplicated by key alone, so ?tag=a in the URL with tag=b in the table sent only tag=a. Only the row the two-way sync mirrored — same key and same value — is folded away now. Repeated keys are the case the sender goes out of its way to preserve, since the APIs that sign a query string verbatim depend on it.
  • Capturing a response example rewrote the body. It was parsed and re-serialised even when the redaction sweep found nothing, which is lossy in ways that matter for a file whose whole job is to record what an endpoint really returned: an id past Number.MAX_SAFE_INTEGER came back a different number, and a duplicate key collapsed. The bytes are now left alone unless something was actually redacted.
  • A CR or LF in a multipart field name could inject headers into the part. Kurlo escapes those, but only on the branch taken when the row names its own Content-Type; without one it fell through to mime/multipart's helpers, which escape quotes and leave line breaks intact. Every part is now written through the same escaping.
  • An empty form-data or x-www-form-urlencoded body was framed on a GET. The raw body types already treated an empty payload on a method that conventionally carries none as no body at all; these two did not.

Changed

  • Code comments were removed across the repository, at the maintainer's request. What stays is anything that instructs a tool rather than a reader: //go:build and //go:embed, //nolint, eslint-disable, svelte-ignore. Each language was cut with its own parser rather than a regular expression — Go through go/scanner, TypeScript and the Svelte <script> blocks through the TypeScript parser, stylesheets through a CSS scanner that tracks strings — so a // inside a string or a regex literal was never mistaken for a comment. Go token streams were compared before and after across every file and are identical, the YAML workflows were parsed both ways and compared as documents, and the generated Wails bindings were left alone because CI checks them against the generator's own output.
  • The README no longer understates what is there: OAuth 2.0 lists the Password and Device Code grants added in 1.4.0, the per-request settings mention the proxy, and the scripting section gives the configurable timeout rather than only the 2-second default — and stops listing require as disabled two paragraphs after describing what it resolves.