Nullean.HttpFileParser
0.11.0
See the version list below for details.
dotnet add package Nullean.HttpFileParser --version 0.11.0
NuGet\Install-Package Nullean.HttpFileParser -Version 0.11.0
<PackageReference Include="Nullean.HttpFileParser" Version="0.11.0" />
<PackageVersion Include="Nullean.HttpFileParser" Version="0.11.0" />
<PackageReference Include="Nullean.HttpFileParser" />
paket add Nullean.HttpFileParser --version 0.11.0
#r "nuget: Nullean.HttpFileParser, 0.11.0"
#:package Nullean.HttpFileParser@0.11.0
#addin nuget:?package=Nullean.HttpFileParser&version=0.11.0
#tool nuget:?package=Nullean.HttpFileParser&version=0.11.0
Nullean.HttpFileParser
Parse, lint and run .http request files: the format of Visual Studio 17.8+, the VS Code REST Client and the
JetBrains HTTP Client, in its script-free forms. No dependencies beyond the BCL; AOT and trim clean. MIT.
@host = https://localhost:5001
# @name login
POST {{host}}/login
Content-Type: application/json
{ "user": "ada", "password": "{{$processEnv SHOP_PASSWORD}}" }
###
GET {{host}}/orders?since={{$datetime iso8601 -1 d}}
Authorization: Bearer {{login.response.body.$.token}}
Parse and lint
using Nullean.HttpFileParser;
var file = HttpFile.Load("api.http"); // throws HttpFileParseException listing every problem
foreach (var request in file.Requests)
Console.WriteLine($"{request.Line}: {request.RequestLine}");
var environment = HttpEnvironment.Load(file.Path, "dev");
foreach (var problem in file.Validate(environment))
Console.WriteLine(problem); // api.http:12: unknown variable 'hots'
Every error is file:line: message, and parsing reports all of them at once.
Run
var result = await HttpFileRunner.RunAsync(file, client, new HttpFileRunOptions { Environment = "dev" });
foreach (var exchange in result.Exchanges.Select(result.Redact))
Console.WriteLine($"{exchange.Request.RequestLine} -> {exchange.Response.StatusCode}");
if (result.Failure is { } failure)
Console.WriteLine(failure); // api.http:7: Connection refused (localhost:5001)
- Requests run in file order. The run stops at the first request that cannot be resolved, sent or read, and keeps the exchanges before it. A 404 or 500 is a response, not a failure.
- A URL starting with
/resolves againstHttpClient.BaseAddress, so one file runs against aWebApplicationFactoryclient and, with@host, against a deployed host. - The runner follows redirects itself so that
# @no-redirectworks per request. Give it a client that does not:new HttpClient(new SocketsHttpHandler { AllowAutoRedirect = false }), or forWebApplicationFactory,factory.CreateClient(new() { AllowAutoRedirect = false }). With no client, it creates one that decompresses and keeps a cookie jar (# @no-cookie-jaropts a request out). - A body a client left compressed (
gzip,deflate,br) is decoded;Response.ContentEncodingsays which. - Each exchange holds the request as written, the request as sent, the response and its body bytes.
What it understands
- Requests separated by
###(### namenames the next request),# @name login,#and//comments. METHOD URL [HTTP/1.1|HTTP/2|HTTP/3],GETwhen the method is left out,?/&and indented continuation lines.- Headers, a blank line, then the body.
< ./filesends a file,<@ ./filesubstitutes variables in it first, andmultipart/*bodies can mix text and< ./filelines. - File variables
@name = value, visible to what follows them. http-client.env.jsonenvironments, found in the file's folder or above:$shareddefaults, the named environment, thenhttp-client.env.json.userorhttp-client.private.env.jsonon top. File variables beat them;HttpFileRunOptions.Variablesbeats everything.{{$guid}},{{$uuid}},{{$random.uuid}},{{$randomInt [min max]}}(max exclusive),{{$datetime ...}},{{$localDatetime ...}},{{$timestamp}},{{$isoTimestamp}}with offsets such as-1 d,{{$processEnv NAME}},{{$env.NAME}},{{$dotenv NAME}}and{{$secret Name}}.{{login.response.body.$.token}},{{login.response.body.*}},{{login.response.headers.Location}}and the same withrequest. JSONPath supports$,.name,["name"]and[n].# @no-redirect,# @no-cookie-jar,# @timeout 30.# @readonly(a request that only reads, though it is not a GET; sent by a run withHttpFileRunOptions.ReadOnly, which refuses every other write) and# @expectchecks after the response:status 200or2xx,header content-type ~ json,json $.a[*].b equals|contains value. The run stops at the first that does not hold.
Refused with a reason: JetBrains scripts (> {% %}, < {% %}, > handler.js), response redirection (>> file),
@prompt, $aadToken, GraphQL requests, cURL commands and XPath.
Secrets and redaction
Environment entries such as { "provider": "AspnetUserSecrets", "secretName": "Shop:ApiKey" } are read from .NET user
secrets. The id comes from HttpFileRunOptions.UserSecretsId, else the [UserSecretsId] attribute of
SecretsAssembly, else <UserSecretsId> in the nearest project file above the .http file.
HttpFileRunOptions.Secrets is asked first, and is the source for other providers and {{$secret Name}}.
Every value from a secret, $processEnv, $env, $dotenv or a .user/.private environment file is recorded.
result.Redact(text) and result.Redact(exchange) put the reference back ({{$processEnv SHOP_PASSWORD}}),
longest value first; failure messages are already redacted. A sensitive value shorter than 4 characters fails the run,
because replacing it everywhere would mangle unrelated text.
Deterministic runs
Pass TimeProvider and a seeded Random in HttpFileRunOptions to make $datetime, $guid and $randomInt
repeatable.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Nullean.HttpFileParser:
| Package | Downloads |
|---|---|
|
Nullean.Snapshots.Http
HTTP snapshots for Nullean.Snapshots: snapshot an HttpResponseMessage, or run a .http file and compare every response, status, chosen headers and JSON bodies as trees, with secrets redacted. |
GitHub repositories
This package is not used by any popular GitHub repositories.