{"id":18575429,"url":"https://github.com/brandonhenricks/restsharp.requestbuilder","last_synced_at":"2025-12-28T21:54:02.412Z","repository":{"id":127176045,"uuid":"152439229","full_name":"brandonhenricks/RestSharp.RequestBuilder","owner":"brandonhenricks","description":".NET Standard Library for creating RestRequest objects using Fluent Syntax.","archived":false,"fork":false,"pushed_at":"2025-01-30T18:32:48.000Z","size":64,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-31T16:53:39.697Z","etag":null,"topics":["csharp","csharp-code","csharp-library","restsharp"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brandonhenricks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-10-10T14:41:20.000Z","updated_at":"2025-01-30T18:32:04.000Z","dependencies_parsed_at":"2025-05-16T09:00:54.958Z","dependency_job_id":null,"html_url":"https://github.com/brandonhenricks/RestSharp.RequestBuilder","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/brandonhenricks/RestSharp.RequestBuilder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonhenricks%2FRestSharp.RequestBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonhenricks%2FRestSharp.RequestBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonhenricks%2FRestSharp.RequestBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonhenricks%2FRestSharp.RequestBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brandonhenricks","download_url":"https://codeload.github.com/brandonhenricks/RestSharp.RequestBuilder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonhenricks%2FRestSharp.RequestBuilder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273068841,"owners_count":25039911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","csharp-code","csharp-library","restsharp"],"created_at":"2024-11-06T23:19:47.909Z","updated_at":"2025-12-28T21:54:02.400Z","avatar_url":"https://github.com/brandonhenricks.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RestSharp.RequestBuilder\n\n[![NuGet Status](https://img.shields.io/nuget/v/RestSharp.RequestBuilder.svg?style=flat)](https://www.nuget.org/packages/RestSharp.RequestBuilder/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nRestSharp.RequestBuilder is a .NET Standard library that provides a fluent, chainable API for constructing REST requests using RestSharp. It offers a clean, expressive syntax for building complex HTTP requests with headers, authentication, parameters, files, and request bodies—all while maintaining strong type safety and minimal surface area.\n\n## Overview\n\nThe library's primary goal is to aid in creating `RestRequest` objects using Fluent Syntax, reducing boilerplate and improving readability. The `RequestBuilder` class acts as a general-purpose wrapper for the `IRestRequest` object. It was created to help with projects that use the RestSharp Client to interact with third-party APIs.\n\n## Technology Stack\n\n- **Target Framework**: .NET Standard 2.0 (compatible with .NET Framework 4.6.1+, .NET Core 2.0+, and .NET 5+)\n- **Build/Test Frameworks**: .NET 8.0, .NET 9.0, .NET Core 2.1\n- **Test Framework**: MSTest (Microsoft.VisualStudio.TestTools.UnitTesting)\n- **HTTP Client**: RestSharp (core dependency)\n- **Static Analysis**: CSharpAnalyzers, SonarAnalyzer.CSharp\n- **Code Link Embedding**: Microsoft.SourceLink.GitHub\n\n## Installation\n\nInstall the RestSharp.RequestBuilder NuGet package from the .NET Core CLI:\n\n```shell\ndotnet add package RestSharp.RequestBuilder\n```\n\nOr from the NuGet package manager:\n\n```shell\nInstall-Package RestSharp.RequestBuilder\n```\n\n## Getting Started\n\n### Basic Usage\n\nHere are the two primary ways to create a RestRequest with RestSharp.RequestBuilder:\n\n**Using the RequestBuilder constructor:**\n```csharp\nvar builder = new RequestBuilder(\"user\");\n\nvar request = builder\n    .SetFormat(DataFormat.Json)\n    .SetMethod(Method.Get)\n    .AddHeader(\"test-header\", \"value\")\n    .Create();\n```\n\n**Using the fluent extension method on RestRequest:**\n```csharp\nvar request = new RestRequest().WithBuilder(\"user\")\n    .SetFormat(DataFormat.Json)\n    .SetMethod(Method.Get)\n    .AddHeader(\"test-header\", \"value\")\n    .Create();\n```\n\nBoth approaches return a fully configured `RestRequest` ready for use with a RestSharp `RestClient`.\n\n### Query Parameters and URL Segments\n\nThe library provides convenient fluent methods to add query string parameters and URL segments without manually creating Parameter objects:\n\n```csharp\n// Add query parameters individually\nvar request = new RestRequest().WithBuilder(\"users\")\n    .AddQueryParameter(\"page\", 1)\n    .AddQueryParameter(\"limit\", 50)\n    .AddQueryParameter(\"sort\", \"desc\")\n    .Create();\n```\n\n```csharp\n// Add multiple query parameters at once\nvar request = new RestRequest().WithBuilder(\"users\")\n    .AddQueryParameters(new Dictionary\u003cstring, object\u003e\n    {\n        { \"page\", 1 },\n        { \"limit\", 50 },\n        { \"sort\", \"desc\" }\n    })\n    .Create();\n```\n\n```csharp\n// Add URL segments for parameterized routes\nvar request = new RestRequest().WithBuilder(\"users/{id}/posts\")\n    .AddUrlSegment(\"id\", 123)\n    .AddQueryParameter(\"page\", 1)\n    .Create();\n```\n\n**Features:**\n\n- All values are automatically converted to strings using `InvariantCulture`\n- Duplicate parameters are replaced (case-insensitive)\n- All methods support fluent chaining\n- Null values in bulk operations are skipped\n\n### Authentication\n\nThe library provides first-class fluent authentication helpers for common HTTP authentication methods:\n\n#### Bearer Token Authentication\n\n```csharp\nvar request = new RestRequest().WithBuilder(\"api/me\")\n    .WithBearerToken(\"your-bearer-token\")\n    .Create();\n```\n\n#### Basic Authentication\n\n```csharp\nvar request = new RestRequest().WithBuilder(\"admin\")\n    .WithBasicAuth(\"username\", \"password\")\n    .Create();\n```\n\nThe credentials are automatically Base64-encoded as required by the HTTP Basic authentication standard.\n\n#### API Key Authentication\n\n```csharp\n// Using default header name (X-API-Key)\nvar request = new RestRequest().WithBuilder(\"secure\")\n    .WithApiKey(\"your-api-key\")\n    .Create();\n\n// Using custom header name\nvar request = new RestRequest().WithBuilder(\"secure\")\n    .WithApiKey(\"your-api-key\", \"X-Custom-Api-Key\")\n    .Create();\n```\n\n#### OAuth2 Authentication\n\n```csharp\nvar request = new RestRequest().WithBuilder(\"api/protected\")\n    .WithOAuth2(\"oauth2-access-token\")\n    .Create();\n```\n\n**Authentication Features:**\n\n- All authentication methods chain with other builder methods\n- Setting a new authentication automatically replaces any existing Authorization header\n- All methods validate input and throw `ArgumentNullException` for null or empty values\n- Full XML documentation for IntelliSense support\n\n### Header Convenience Methods\n\nThe library provides fluent convenience methods for common HTTP headers, making it easier to set standard headers without having to remember exact header names or worry about typos:\n\n#### Accept Header\n\n```csharp\n// Specify custom Accept header\nvar request = new RestRequest().WithBuilder(\"api/data\")\n    .WithAccept(\"application/json\")\n    .Create();\n\n// Convenient shortcuts for common media types\nvar jsonRequest = new RestRequest().WithBuilder(\"api/data\")\n    .WithAcceptJson()  // Sets Accept: application/json\n    .Create();\n\nvar xmlRequest = new RestRequest().WithBuilder(\"api/data\")\n    .WithAcceptXml()  // Sets Accept: application/xml\n    .Create();\n```\n\n#### Content-Type Header\n\n```csharp\nvar request = new RestRequest().WithBuilder(\"api/upload\")\n    .SetMethod(Method.Post)\n    .WithContentType(\"application/json\")\n    .AddJsonBody(new { data = \"value\" })\n    .Create();\n```\n\n#### User-Agent Header\n\n```csharp\nvar request = new RestRequest().WithBuilder(\"api/resource\")\n    .WithUserAgent(\"MyCustomClient/1.2.3\")\n    .Create();\n```\n\n#### Custom Authorization Header\n\n```csharp\n// For custom authorization schemes beyond Bearer/Basic\nvar request = new RestRequest().WithBuilder(\"api/protected\")\n    .WithAuthorization(\"Digest\", \"realm=\\\"example.com\\\"\")\n    .Create();\n\n// You can still use the specific helpers for common schemes\nvar bearerRequest = new RestRequest().WithBuilder(\"api/me\")\n    .WithBearerToken(\"token123\")  // Shortcut for WithAuthorization(\"Bearer\", \"token123\")\n    .Create();\n```\n\n#### Conditional Request Headers (ETags)\n\n```csharp\n// If-Match for optimistic concurrency control\nvar updateRequest = new RestRequest().WithBuilder(\"api/resource/{id}\")\n    .AddUrlSegment(\"id\", \"123\")\n    .SetMethod(Method.Put)\n    .WithIfMatch(\"\\\"v1-abc123\\\"\")\n    .AddJsonBody(new { name = \"Updated Name\", version = \"v2\" })\n    .Create();\n\n// If-None-Match for efficient caching\nvar cacheRequest = new RestRequest().WithBuilder(\"api/resource/{id}\")\n    .AddUrlSegment(\"id\", \"123\")\n    .WithIfNoneMatch(\"\\\"v1-abc123\\\"\")\n    .Create();\n```\n\n#### Referer and Origin Headers\n\n```csharp\n// Useful for CORS and tracking\nvar request = new RestRequest().WithBuilder(\"api/external\")\n    .WithReferer(\"https://myapp.com/page\")\n    .WithOrigin(\"https://myapp.com\")\n    .Create();\n```\n\n#### Combining Multiple Headers\n\n```csharp\n// All header methods chain fluently\nvar request = new RestRequest().WithBuilder(\"api/items\")\n    .WithAcceptJson()\n    .WithContentType(\"application/json\")\n    .WithUserAgent(\"MyClient/1.0.0\")\n    .WithBearerToken(\"mytoken\")\n    .WithIfNoneMatch(\"\\\"abc1234\\\"\")\n    .WithReferer(\"https://example.com/page\")\n    .WithOrigin(\"https://example.com\")\n    .AddQueryParameter(\"page\", 1)\n    .Create();\n```\n\n**Header Method Features:**\n\n- All header methods use standard HTTP header casing (e.g., 'Accept', 'Content-Type', 'User-Agent')\n- Duplicate headers are automatically replaced when called multiple times\n- All methods validate input and throw `ArgumentNullException` for null or empty values\n- Seamless integration with other builder methods for flexible request construction\n- Full XML documentation for IntelliSense support\n\n### Request Bodies\n\nThe library provides convenient shortcut methods for adding request bodies with common content types:\n\n#### JSON Body\n\n```csharp\n// Add a JSON body to the request\nvar request = new RestRequest().WithBuilder(\"api/users\")\n    .SetMethod(Method.Post)\n    .AddJsonBody(new { name = \"John Doe\", email = \"john@example.com\" })\n    .Create();\n```\n\nThe `AddJsonBody` method automatically sets the request format to `DataFormat.Json` and serializes the body object.\n\n#### XML Body\n\n```csharp\n// Add an XML body to the request\nvar request = new RestRequest().WithBuilder(\"api/users\")\n    .SetMethod(Method.Post)\n    .AddXmlBody(new User { Id = 1, Name = \"John Doe\" })\n    .Create();\n```\n\nThe `AddXmlBody` method automatically sets the request format to `DataFormat.Xml` and serializes the body object.\n\n#### Form URL Encoded Body\n\n```csharp\n// Add form-urlencoded data (commonly used for OAuth token requests)\nvar request = new RestRequest().WithBuilder(\"oauth/token\")\n    .SetMethod(Method.Post)\n    .AddFormUrlEncodedBody(new Dictionary\u003cstring, string\u003e\n    {\n        { \"grant_type\", \"password\" },\n        { \"username\", \"user@example.com\" },\n        { \"password\", \"secretpassword\" }\n    })\n    .Create();\n```\n\nThe `AddFormUrlEncodedBody` method adds each key-value pair as a form parameter (`GetOrPost` parameter type).\n\n**Body Method Features:**\n\n- All body methods validate input and throw `ArgumentNullException` for null values\n- Body methods chain with other builder methods for flexible request construction\n- `AddJsonBody` and `AddXmlBody` automatically set the appropriate request format\n- `AddFormUrlEncodedBody` skips null values in the dictionary\n- Setting a new body replaces any previously set body\n- Full XML documentation for IntelliSense support\n\n**Important:** Do not mix `AddJsonBody`/`AddXmlBody` with `AddFormUrlEncodedBody` on the same request builder. These represent mutually exclusive ways of sending data:\n\n- `AddJsonBody`/`AddXmlBody` set a request body (serialized as JSON or XML)\n- `AddFormUrlEncodedBody` adds form parameters (sent as `application/x-www-form-urlencoded`)\n\nChoose one approach based on your API requirements. Mixing both would create a semantically invalid request.\n\n**Note:** These methods work with RestSharp's serialization pipeline. For JSON, ensure you have configured an appropriate JSON serializer (RestSharp uses `System.Text.Json` by default). For XML, RestSharp uses the built-in .NET XML serializer.\n\n## Project Architecture\n\nRestSharp.RequestBuilder implements a **Fluent Builder Pattern** with the following design principles:\n\n### Key Components\n\n- **RequestBuilder.cs**: The sealed core implementation that accumulates REST request configuration (headers, parameters, cookies, files, body, format, method, timeout)\n- **IRequestBuilder.cs**: The public contract defining all builder operations with fluent chaining semantics\n- **RestRequestExtensions.cs**: Extension methods providing ergonomic entry points via `WithBuilder()` on `RestRequest`\n- **Models/**: Supporting types including `CookieValue`, `CookieValueComparer`, and polymorphic `FileAttachment` classes\n\n### Design Patterns\n\n1. **Fluent Builder Pattern**: Every public method returns `IRequestBuilder` to enable method chaining\n2. **Single Responsibility**: The builder focuses solely on accumulating configuration without side effects\n3. **Sealed Implementation**: `RequestBuilder` is sealed to prevent subclass override and maintain invariants\n4. **State Encapsulation**: All configuration is stored in private fields until `Create()` is called, enabling safe repeated calls\n5. **Case-Insensitive Deduplication**: Parameters and headers are deduplicated using `StringComparison.InvariantCultureIgnoreCase`\n\n## Project Structure\n\n```\nRestSharp.RequestBuilder/\n├── src/RestSharp.RequestBuilder/\n│   ├── RequestBuilder.cs              # Core builder class (743 lines)\n│   ├── Extensions/RestRequestExtensions.cs  # Entry points\n│   ├── Interfaces/IRequestBuilder.cs  # Public contract (338 lines)\n│   └── Models/\n│       ├── CookieValue.cs            # Immutable cookie POCO\n│       ├── CookieValueComparer.cs    # Case-insensitive equality\n│       └── FileAttachment.cs         # Polymorphic file abstraction\n├── tests/RestSharp.RequestBuilder.UnitTests/\n│   ├── RequestBuilderTests.cs        # 100+ test cases\n│   └── RestSharp.RequestBuilder.UnitTests.csproj\n├── .github/\n│   ├── instructions/                 # Comprehensive documentation\n│   ├── copilot-instructions.md       # AI development guide\n│   └── workflows/                    # CI/CD pipeline definitions\n├── RestSharp.RequestBuilder.sln      # Solution root\n├── Directory.Build.props             # Shared build properties\n├── Directory.Packages.props          # Centralized package versions\n└── global.json                       # .NET SDK version pinning\n```\n\n## Development Setup\n\n### Prerequisites\n\n- **.NET 8.0 SDK** or later (verify with `dotnet --version`)\n- Git for version control\n- Visual Studio 2022, VS Code, or JetBrains Rider\n\n### Getting Started\n\n```powershell\n# Clone the repository\ngit clone https://github.com/brandonhenricks/RestSharp.RequestBuilder.git\ncd RestSharp.RequestBuilder\n\n# Restore packages\ndotnet restore\n\n# Build the solution\ndotnet build RestSharp.RequestBuilder.sln -c Release\n\n# Run tests\ndotnet test RestSharp.RequestBuilder.sln -c Release\n\n# Package locally (optional)\ndotnet pack src/RestSharp.RequestBuilder/ -c Release -o ./artifacts\n```\n\n## Key Features\n\n- **Fluent API**: Chainable methods for expressive request construction\n- **Comprehensive Authentication**: Built-in helpers for Bearer, Basic, API Key, and OAuth2\n- **Flexible Parameters**: Query parameters, URL segments, and intelligent deduplication\n- **File Handling**: Seamless support for file paths, byte arrays, and streams\n- **Content Negotiation**: Convenience methods for Accept, Content-Type, and custom headers\n- **Body Serialization**: JSON, XML, and form URL-encoded shortcuts\n- **Cookie Management**: Case-insensitive cookie handling via `CookieContainer`\n- **Input Validation**: Null checks and type safety throughout\n- **Broad Compatibility**: .NET Standard 2.0 support for maximum reach\n- **Zero Runtime Dependencies**: Only RestSharp is required\n\n## Coding Standards\n\nThe project adheres to strict coding standards:\n\n- **Naming Conventions**: Methods use action verbs (Add*, Remove*, Set*, With*); case-insensitive for parameters/headers\n- **Method Organization**: Organized by functional category (Body, File, Header, Parameter, Cookie, Configuration, Authentication)\n- **Documentation**: Comprehensive XML comments for IntelliSense\n- **Analyzers**: CSharpAnalyzers and SonarAnalyzer.CSharp enforce consistency\n- **Test-Driven**: All public methods have associated unit tests covering happy path, null guards, and edge cases\n\n## Testing\n\nThe project includes 100+ MSTest unit tests covering:\n\n- **Constructor validation**: Null guards, resource parsing, default values\n- **Body operations**: JSON, XML, and form-encoded serialization\n- **File operations**: Disk paths, byte arrays, and streams\n- **Header operations**: Case-insensitive deduplication and replacement\n- **Parameter operations**: Deduplication, URL segments, query parameters\n- **Cookie operations**: Case-insensitive handling via `CookieContainer`\n- **Authentication**: Bearer, Basic, API Key, OAuth2 methods\n- **Content negotiation**: Accept and Content-Type headers\n- **Complex scenarios**: Mixed file sources, chained operations\n\nRun tests with:\n\n```powershell\ndotnet test RestSharp.RequestBuilder.sln -c Release\n```\n\n## Contributing\n\nContributions are welcome! Please follow these guidelines:\n\n1. **Create a feature branch**: `git checkout -b feature/your-feature-name`\n2. **Follow coding standards**: Review [CODING_STANDARDS.instructions.md](.github/instructions/CODING_STANDARDS.instructions.md)\n3. **Add tests**: All new public methods must have associated tests\n4. **Run the full build**: `dotnet build` and `dotnet test` must pass\n5. **Update README**: If adding user-visible features, update this file with examples\n6. **Maintain backward compatibility**: The .NET Standard surface is immutable\n\n### Before Submitting a PR\n\n- [ ] `dotnet build RestSharp.RequestBuilder.sln` passes\n- [ ] `dotnet test RestSharp.RequestBuilder.sln` passes all tests\n- [ ] New public APIs have XML documentation\n- [ ] Test coverage for new methods (happy path, null guards, edge cases)\n- [ ] README updated if consumer-visible behavior changed\n- [ ] No secrets or real tokens in code/tests\n\n## Detailed Documentation\n\nFor deeper information, see the [.github/instructions](.github/instructions) directory:\n\n- [ARCHITECTURE.instructions.md](.github/instructions/ARCHITECTURE.instructions.md) — Design decisions and component interactions\n- [CODING_STANDARDS.instructions.md](.github/instructions/CODING_STANDARDS.instructions.md) — Naming, style, and documentation conventions\n- [PROJECT_FOLDER_STRUCTURE.instructions.md](.github/instructions/PROJECT_FOLDER_STRUCTURE.instructions.md) — Directory organization and key files\n- [TECHNOLOGY_STACK.instructions.md](.github/instructions/TECHNOLOGY_STACK.instructions.md) — Dependencies and version management\n- [UNIT_TESTS.instructions.md](.github/instructions/UNIT_TESTS.instructions.md) — Testing strategy and coverage\n- [WORKFLOW_ANALYSIS.instructions.md](.github/instructions/WORKFLOW_ANALYSIS.instructions.md) — Build, test, and release workflows\n\nSee also [AGENTS.md](AGENTS.md) for agent-specific development context and [copilot-instructions.md](.github/copilot-instructions.md) for architectural deep dives.\n\n## License\n\nRestSharp.RequestBuilder is licensed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonhenricks%2Frestsharp.requestbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrandonhenricks%2Frestsharp.requestbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonhenricks%2Frestsharp.requestbuilder/lists"}