RepoPilotOpen in app →

tmenier/Flurl

Fluent URL builder and testable HTTP client for .NET

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 7 active contributors
  • MIT licensed
  • CI configured
Show 3 more →
  • Tests present
  • Stale — last commit 1y ago
  • Concentrated ownership — top contributor handles 72% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tmenier/flurl)](https://repopilot.app/r/tmenier/flurl)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tmenier/flurl on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tmenier/Flurl

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tmenier/Flurl shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 7 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 1y ago
  • ⚠ Concentrated ownership — top contributor handles 72% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tmenier/Flurl repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tmenier/Flurl.

What it runs against: a local clone of tmenier/Flurl — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tmenier/Flurl | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch dev exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 523 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tmenier/Flurl</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tmenier/Flurl. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tmenier/Flurl.git
#   cd Flurl
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tmenier/Flurl and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tmenier/Flurl(\\.git)?\\b" \\
  && ok "origin remote is tmenier/Flurl" \\
  || miss "origin remote is not tmenier/Flurl (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify dev >/dev/null 2>&1 \\
  && ok "default branch dev exists" \\
  || miss "default branch dev no longer exists"

# 4. Critical files exist
test -f "src/Flurl/Url.cs" \\
  && ok "src/Flurl/Url.cs" \\
  || miss "missing critical file: src/Flurl/Url.cs"
test -f "src/Flurl.Http/FlurlClient.cs" \\
  && ok "src/Flurl.Http/FlurlClient.cs" \\
  || miss "missing critical file: src/Flurl.Http/FlurlClient.cs"
test -f "src/Flurl.Http/FlurlRequest.cs" \\
  && ok "src/Flurl.Http/FlurlRequest.cs" \\
  || miss "missing critical file: src/Flurl.Http/FlurlRequest.cs"
test -f "src/Flurl.Http/Testing/HttpTest.cs" \\
  && ok "src/Flurl.Http/Testing/HttpTest.cs" \\
  || miss "missing critical file: src/Flurl.Http/Testing/HttpTest.cs"
test -f "src/Flurl.Http/Configuration/FlurlHttpSettings.cs" \\
  && ok "src/Flurl.Http/Configuration/FlurlHttpSettings.cs" \\
  || miss "missing critical file: src/Flurl.Http/Configuration/FlurlHttpSettings.cs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 523 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~493d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tmenier/Flurl"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Flurl is a fluent, async .NET library that provides a lightweight URL builder and testable HTTP client with a clean fluent API. It eliminates boilerplate for constructing URLs and making HTTP requests, and includes an HttpTest fake-HTTP testing harness (see README example) for mocking HTTP calls in unit tests without external services. Multi-package structure: src/Flurl.Http is the main HTTP client package with Configuration/, Content/, and core files like FlurlClient.cs and FlurlCall.cs; src/Flurl.Http.Newtonsoft provides Newtonsoft.Json integration; src/Flurl.CodeGen is a code-generation utility for extension methods. All packages are assembled in Flurl.sln.

👥Who it's for

.NET developers building API clients or web services who want readable, chainable HTTP code and easy-to-write isolated unit tests without setting up mock servers or HTTP mocking libraries. Both library authors and application developers use it.

🌱Maturity & risk

Production-ready and actively maintained. The project has high NuGet download counts, a published website (flurl.dev), organized GitHub Actions CI/CD pipelines (ci.yml, test.yml, publish.yml), and appears to have regular releases via draft-release.yml and publish.yml workflows. The codebase is substantial (569k C# lines) with established package structure.

Low risk for a mature library. It's a single-maintainer project (tmenier), but has clear CI/CD automation, NuGet versioning, and no obvious dependency sprawl visible in the file structure. Risk is primarily that breaking API changes could affect downstream consumers—mitigated by semantic versioning through NuGet. No immediate abandonment signals.

Active areas of work

Based on the file structure, the project is maintaining active CI/CD workflows (test.yml runs on each commit, publish.yml handles releases). The presence of draft-release.yml and publish.yml suggests organized release management. Without commit history, exact current work is unclear, but the organized workflow structure and NuGet package versions indicate ongoing stability and release cycles.

🚀Get running

Clone and build with .NET tooling: git clone https://github.com/tmenier/Flurl.git && cd Flurl && dotnet build Flurl.sln. Install NuGet package for use: dotnet add package Flurl.Http. For local development, run tests via dotnet test (test structure inferred from test.yml workflow).

Daily commands: Build: dotnet build Flurl.sln. Test: dotnet test Flurl.sln. For package publishing, CI/CD handles it via publish.yml. For local testing: individual test projects can be run with dotnet test src/path/to/Tests.csproj.

🗺️Map of the codebase

  • src/Flurl/Url.cs — Core URL builder class that provides the fluent API for constructing and manipulating URLs; all URL operations depend on this abstraction.
  • src/Flurl.Http/FlurlClient.cs — Main HTTP client entry point that orchestrates requests, handles configuration, and manages the request/response lifecycle.
  • src/Flurl.Http/FlurlRequest.cs — Encapsulates a single HTTP request with headers, body, and settings; consumed by FlurlClient to build and execute HTTP calls.
  • src/Flurl.Http/Testing/HttpTest.cs — Testing framework that intercepts and records HTTP calls for assertion and mocking; essential for understanding the test harness.
  • src/Flurl.Http/Configuration/FlurlHttpSettings.cs — Global and per-client settings container for timeouts, serializers, event handlers, and retry policies; controls library behavior.
  • src/Flurl.Http/FlurlCall.cs — Immutable record of a single HTTP call (request + response) used for event handling, testing assertions, and debugging.
  • src/Flurl.Http/GeneratedExtensions.cs — Auto-generated convenience methods for HTTP verbs (Get, Post, Put, etc.) that form the public fluent API.

🛠️How to make changes

Add a new HTTP verb convenience method

  1. Define the new verb in src/Flurl.CodeGen/Metadata.cs if not already in HttpMethod enum (src/Flurl.CodeGen/Metadata.cs)
  2. Add an HttpExtensionMethod entry in Program.cs metadata to generate the overload (src/Flurl.CodeGen/Program.cs)
  3. Run the code generator (part of build) to auto-populate GeneratedExtensions.cs (src/Flurl.Http/GeneratedExtensions.cs)
  4. Add tests in test/Flurl.Test/Http/HttpMethodTests.cs to verify the new verb works (test/Flurl.Test/Http/HttpMethodTests.cs)

Add a custom serializer for a new format

  1. Create a new class implementing ISerializer in src/Flurl.Http/Configuration/ISerializer.cs (src/Flurl.Http/Configuration/ISerializer.cs)
  2. Implement Serialize/Deserialize with your format logic (e.g., XML, MessagePack) (src/Flurl.Http/Configuration/DefaultJsonSerializer.cs)
  3. Register it globally in FlurlHttpSettings.JsonSerializer or per-client in FlurlClientBuilder (src/Flurl.Http/Configuration/FlurlHttpSettings.cs)
  4. Add tests in test/Flurl.Test/Http/ to verify serialization round-trips (test/Flurl.Test/Http/GlobalConfigTests.cs)

Add a new request lifecycle event

  1. Define a new delegate or event in FlurlEventHandler.cs following the existing pattern (OnBeforeCall, OnAfterCall, etc.) (src/Flurl.Http/FlurlEventHandler.cs)
  2. Add the event property to FlurlHttpSettings and make it inheritable via ISettingsContainer (src/Flurl.Http/Configuration/FlurlHttpSettings.cs)
  3. Invoke the event at the appropriate point in FlurlClient.SendAsync or FlurlRequest construction (src/Flurl.Http/FlurlClient.cs)
  4. Write integration tests in test/Flurl.Test/Http/EventHandlerTests.cs (test/Flurl.Test/Http/EventHandlerTests.cs)

Add support for a new test assertion

  1. Add a fluent method to HttpCallAssertion.cs that checks a property of FlurlCall (src/Flurl.Http/Testing/HttpCallAssertion.cs)
  2. Follow the pattern: check the condition and throw HttpTestException with a clear message if it fails (src/Flurl.Http/Testing/HttpTestException.cs)
  3. Add test cases in test/Flurl.Test/Http/TestingTests.cs to verify the assertion works and provides good error messages (test/Flurl.Test/Http/TestingTests.cs)

🔧Why these technologies

  • System.Text.Json (default) + pluggable ISerializer — Avoids heavyweight external dependencies by default; ISerializer abstraction allows users to swap in Newtonsoft.Json or other serializers as needed.
  • HttpClient + HttpMessageHandler — undefined

🪤Traps & gotchas

No obvious trap-inducing env vars or mandatory external services from the file structure. Key gotcha: FlurlClientCache is a singleton per URL base—tests must use HttpTest to isolate and avoid cross-test contamination (hence using var httpTest = new HttpTest() in README). Breaking change risk: fluent API is wide surface; minor method signature changes in core files (FlurlClient, FlurlCall) could break downstream. Newtonsoft integration is optional via separate package.

🏗️Architecture

💡Concepts to learn

  • Fluent Builder Pattern — Core to Flurl's API design; AppendPathSegment().SetQueryParams().WithOAuthBearerToken().PostJsonAsync() chaining is the fluent builder pattern applied to HTTP requests
  • HttpClient Message Handlers (Handler Interception) — HttpTest likely intercepts HttpClient via custom DelegatingHandler; critical to understand how Flurl's test fake works without mocking the entire HTTP stack
  • ISerializer/Plug-in Serialization Strategy — Flurl abstracts JSON serialization behind ISerializer interface (Configuration/ISerializer.cs); allows swapping between DefaultJsonSerializer and NewtonsoftJsonSerializer at runtime
  • Request/Response Lifecycle Capture (for Testing) — FlurlCall.cs and Captured*Content.cs classes capture request bodies, response bodies, and metadata for assertions in tests without modifying production code
  • Cookie Jar State Management — CookieJar.cs and CookieSession.cs provide session-level cookie persistence across multiple HTTP calls; important for maintaining auth state in sequential API workflows
  • Redirect Policy Configuration — RedirectSettings.cs allows fine-grained control over 3xx response handling; critical for APIs with strict redirect rules or security concerns
  • OAuth Bearer Token Extension — WithOAuthBearerToken() in examples and extensions shows how Flurl simplifies adding Authorization headers for modern API security patterns
  • restsharp/RestSharp — Alternative .NET HTTP client library with similar fluent API and testing support; direct competitor in same ecosystem
  • App-vNext/Polly — Resilience library (retries, circuit breaker) often used alongside Flurl for production HTTP client policies
  • microsoft/Refit — Alternative .NET HTTP client using source generation and interface-based API definitions; different approach to same problem
  • WireMock-Net/WireMock.Net — HTTP mocking library for .NET that pairs with Flurl for integration test scenarios requiring real mock servers
  • tmenier/FluentAssertions — Not by same author but often used with Flurl's HttpTest assertions for readable test expressions

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive tests for CookieJar and CookieSession functionality

The repo has cookie-related classes (CookieJar.cs, CookieSession.cs, CookieCutter.cs, FlurlCookie.cs) but there's no visible test coverage listed in the file structure. Cookie handling is complex (domain validation, expiration, secure/httponly flags) and prone to bugs. Adding unit tests would improve reliability and prevent regressions.

  • [ ] Create test file targeting src/Flurl.Http/CookieJar.cs covering cookie addition, retrieval, and expiration
  • [ ] Create test file for src/Flurl.Http/CookieSession.cs testing session lifecycle and persistence
  • [ ] Add tests for src/Flurl.Http/CookieCutter.cs validating cookie matching logic for domains/paths
  • [ ] Test FlurlCookie.cs covering serialization and domain-matching edge cases

Add integration tests for multipart form data and file uploads

MultipartExtensions.cs exists but file upload/multipart handling is critical functionality that often has platform-specific issues (.NET Framework vs .NET Core). The repo has FileContent.cs and FileUtil.cs but no visible test coverage. Adding integration tests would ensure compatibility across platforms.

  • [ ] Create integration test file for src/Flurl.Http/MultipartExtensions.cs testing multipart form construction
  • [ ] Add tests for src/Flurl.Http/Content/FileContent.cs verifying file streaming and disposal
  • [ ] Test src/Flurl.Http/FileUtil.cs for file existence checks and path handling across Windows/Unix
  • [ ] Add tests for large file uploads with progress tracking if supported by FlurlRequest.cs

Add tests for HTTP status code range parsing and redirect handling

HttpStatusRangeParser.cs and RedirectSettings.cs (in Configuration/) handle critical HTTP semantics but have no visible test coverage. Status code range parsing (e.g., '2xx', '3xx-399') and redirect policies are easy to get wrong and affect all HTTP calls. Comprehensive tests would prevent subtle bugs.

  • [ ] Create test file for src/Flurl.Http/HttpStatusRangeParser.cs covering range formats ('2xx', '200-299', '200,301', etc.)
  • [ ] Add tests for src/Flurl.Http/Configuration/RedirectSettings.cs validating follow/block redirect logic
  • [ ] Test src/Flurl.Http/FlurlHttpException.cs exception handling with various status codes
  • [ ] Add edge case tests for malformed range strings and boundary conditions

🌿Good first issues

  • Add integration tests or documented examples for the CookieJar/CookieSession functionality in src/Flurl.Http/CookieJar.cs—file exists but usage patterns in test suite may be sparse.
  • Document or add examples for the FileContent and DownloadExtensions file-handling APIs (src/Flurl.Http/FileContent.cs, DownloadExtensions.cs) in the README or a tutorial doc—powerful feature but not shown in main README.
  • Enhance the CodeGen tool (src/Flurl.CodeGen) to generate async-only overloads or document its current output; the tool exists but usage/maintenance unclear from file structure.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 36a3fa2 — happy new year! (Todd)
  • aa7bd45 — CI - improved readability (tmenier)
  • c62605b — CI - still struggling with escaping (tmenier)
  • 52d02ac — CI - fix windows shell escaping (tmenier)
  • 7e0ac6d — CI - lots of things wrong, try that again (tmenier)
  • f4f549d — run .NET Framework tests on windows (tmenier)
  • 0bf3b83 — CI error, will upgrading actions fix? (tmenier)
  • 5c0cbd2 — Merge remote-tracking branch 'origin/dev' into dev (Todd)
  • 360c15d — STJ update (vulnerability) (Todd)
  • 93f5668 — Merge pull request #844 from Pyrobolser/patch-1 (tmenier)

🔒Security observations

Flurl is a well-structured HTTP client library with generally solid security practices. No critical vulnerabilities were identified in the static analysis. Main concerns are around encouraging secure credential handling practices, HTTPS enforcement policies, and cookie security attribute configuration. The codebase does not contain hardcoded secrets, SQL injection vectors, or XSS vulnerabilities typical of the analyzed components. Dependency information was not provided for analysis. The project demonstrates good separation of concerns and testing infrastructure. Consider adding explicit security guidelines and optional enforcement mechanisms for HTTPS and cookie security.

  • Medium · Potential OAuth Token Exposure in Code Examples — README.md. The README.md contains example code with OAuth bearer tokens and API keys shown in plain text. While these are examples, this pattern could encourage developers to hardcode credentials in their own implementations. Fix: Update code examples to use environment variables or secure configuration management. Add a security note in documentation about proper credential handling.
  • Medium · Missing HTTPS Enforcement — src/Flurl/Url.cs. The URL builder (Flurl) allows building URLs with any scheme. There's no apparent enforcement preventing users from accidentally or intentionally using insecure HTTP connections for sensitive operations. Fix: Consider adding optional security policies to warn or enforce HTTPS for certain operations. Document best practices for secure HTTPS-only usage.
  • Low · Cookie Handling Without Explicit Security Flags — src/Flurl.Http/Cookie*.cs. Cookie-related files (CookieCutter.cs, CookieJar.cs, CookieSession.cs) exist but without seeing the implementation details, there's potential concern about missing SameSite, Secure, and HttpOnly flags enforcement. Fix: Verify that all cookie operations enforce security attributes (SameSite, Secure, HttpOnly). Add documentation on secure cookie handling.
  • Low · No Apparent Certificate Pinning or TLS Validation — src/Flurl.Http/FlurlClient.cs, src/Flurl.Http/FlurlRequest.cs. As an HTTP client library, there's no visible implementation of certificate pinning or advanced TLS validation options in the file structure, which could be relevant for high-security scenarios. Fix: Add optional support for certificate pinning and custom TLS validation callbacks. Document TLS best practices.
  • Low · Testing Framework Could Mask Security Issues — src/Flurl.Http/Testing/HttpTest.cs. The HttpTest framework (src/Flurl.Http/Testing/) allows mocking HTTP calls, which could encourage testing without proper security validation if not used carefully. Fix: Add documentation and examples showing how to test security features properly. Warn against using test mocks to bypass security checks.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tmenier/Flurl — RepoPilot