├── examples
├── HttpClientToCurl.Sample.InFile
│ ├── Program.cs
│ ├── HttpClientToCurl.Sample.InFile.csproj
│ └── ApiCaller.cs
├── HttpClientToCurl.Sample.InString
│ ├── Program.cs
│ ├── HttpClientToCurl.Sample.InString.csproj
│ └── ApiCaller.cs
├── HttpClientToCurl.Sample.InConsole
│ ├── Program.cs
│ ├── HttpClientToCurl.Sample.InConsole.csproj
│ └── ApiCaller.cs
├── HttpClientToCurl.Sample.InGlobal
│ ├── appsettings.Development.json
│ ├── HttpClientToCurl.Sample.InGlobal.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── appsettings.json
│ └── Controllers
│ │ └── MyController.cs
└── HttpClientToCurl.Sample.InSpecific
│ ├── appsettings.Development.json
│ ├── HttpClientToCurl.Sample.InSpecific.csproj
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── appsettings.json
│ └── Controllers
│ └── MyController.cs
├── src
└── HttpClientToCurl
│ ├── Config
│ ├── StringConfig.cs
│ ├── ConsoleConfig.cs
│ ├── FileConfig.cs
│ ├── LoggerConfig.cs
│ ├── BaseConfig.cs
│ └── CompositConfig.cs
│ ├── Builder
│ ├── Concrete
│ │ ├── Common
│ │ │ ├── Constants.cs
│ │ │ ├── BaseBuilder.cs
│ │ │ └── Extensions.cs
│ │ ├── HttpDeleteBuilder.cs
│ │ ├── HttpGetBuilder.cs
│ │ ├── HttpPutBuilder.cs
│ │ ├── HttpPatchBuilder.cs
│ │ └── HttpPostBuilder.cs
│ ├── Interface
│ │ └── IBuilder.cs
│ └── Generator.cs
│ ├── HttpMessageHandlers
│ ├── HttpMessageHandlerAppender.cs
│ └── CurlGeneratorHttpMessageHandler.cs
│ ├── HttpClientToCurl.csproj
│ ├── Extensions
│ ├── ServiceCollectionExtensions.cs
│ ├── HttpRequestMessageExtensions.cs
│ └── HttpClientExtensions.cs
│ └── Utility
│ └── Helpers.cs
├── HttpClientToCurlGenerator.lutconfig
├── tests
├── HttpMessageHandlerTest
│ ├── UnitTest
│ │ ├── Fakes
│ │ │ ├── FakeServiceProvider.cs
│ │ │ ├── FakeHttpMessageHandler.cs
│ │ │ ├── FakeOptionsMonitor.cs
│ │ │ └── FakeLogger.cs
│ │ ├── Builders
│ │ │ ├── HttpMessageHandlerBuilder.cs
│ │ │ └── CompositConfigBuilder.cs
│ │ ├── HttpMessageHandlerAppenderTests.cs
│ │ ├── ServiceCollectionExtensionsTests.cs
│ │ └── CurlGeneratorHttpMessageHandlerTests.cs
│ └── HttpMessageHandlerTest.csproj
├── HttpRequestMessageToCurlTest
│ ├── HttpRequestMessageToCurlTest.csproj
│ ├── UnitTest
│ │ └── MediaTypes
│ │ │ ├── Json
│ │ │ ├── FailedCurlGeneratorTests.cs
│ │ │ └── SuccessCurlGeneratorTests.cs
│ │ │ └── Xml
│ │ │ └── SuccessCurlGeneratorTests.cs
│ └── FunctionalTest
│ │ └── SuccessScenariosTests.cs
└── HttpClientToCurlTest
│ ├── HttpClientToCurlTest.csproj
│ ├── UnitTest
│ └── MediaTypes
│ │ ├── Json
│ │ ├── FailedCurlGeneratorTests.cs
│ │ └── SuccessCurlGeneratorTests.cs
│ │ └── Xml
│ │ └── SuccessCurlGeneratorTests.cs
│ └── FunctionalTest
│ └── SuccessScenariosTests.cs
├── pre-push
├── .github
└── workflows
│ ├── dotnet.yml
│ └── release.yml
├── Issue_Template.md
├── pre-commit
├── Directory.Build.props
├── LICENSE.md
├── .lutignore
├── HttpClientToCurlGenerator.sln
├── README.md
└── .gitignore
/examples/HttpClientToCurl.Sample.InFile/Program.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Sample.InFile;
2 |
3 | await ApiCaller.MakeApiCall();
4 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InString/Program.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Sample.InString;
2 |
3 | await ApiCaller.MakeApiCall();
4 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/StringConfig.cs:
--------------------------------------------------------------------------------
1 | namespace HttpClientToCurl.Config;
2 |
3 | public sealed class StringConfig : BaseConfig;
4 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InConsole/Program.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Sample.InConsole;
2 |
3 | await ApiCaller.MakeApiCall();
4 |
5 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/ConsoleConfig.cs:
--------------------------------------------------------------------------------
1 | namespace HttpClientToCurl.Config;
2 |
3 | public sealed class ConsoleConfig : BaseConfig
4 | {
5 | public bool EnableCodeBeautification { get; set; } = false;
6 | }
7 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/FileConfig.cs:
--------------------------------------------------------------------------------
1 | namespace HttpClientToCurl.Config;
2 |
3 | public sealed class FileConfig : BaseConfig
4 | {
5 | public string Filename { get; set; }
6 | public string Path { get; set; }
7 | }
8 |
--------------------------------------------------------------------------------
/HttpClientToCurlGenerator.lutconfig:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | true
5 | 180000
6 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/LoggerConfig.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace HttpClientToCurl.Config;
4 |
5 | public class LoggerConfig : BaseConfig
6 | {
7 | public LogLevel LogLevel { get; set; } = LogLevel.Debug;
8 | }
9 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/BaseConfig.cs:
--------------------------------------------------------------------------------
1 | namespace HttpClientToCurl.Config;
2 |
3 | public class BaseConfig
4 | {
5 | public bool TurnOn { get; set; } = true;
6 | public bool NeedAddDefaultHeaders { get; set; } = true;
7 | public bool EnableCompression { get; set; } = false;
8 | }
9 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/Common/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace HttpClientToCurl.Builder.Concrete.Common;
2 |
3 | public static class Constants
4 | {
5 | internal const string ContentLength = "Content-Length";
6 | internal const string FormUrlEncodedContentType = "application/x-www-form-urlencoded";
7 | }
8 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Interface/IBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Config;
2 |
3 | namespace HttpClientToCurl.Builder.Interface;
4 |
5 | public interface IBuilder
6 | {
7 | string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config);
8 | string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config);
9 | }
10 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Fakes/FakeServiceProvider.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.HttpMessageHandlers;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Fakes;
4 |
5 | public class FakeServiceProvider(object service) : IServiceProvider
6 | {
7 | private readonly object _service = service;
8 |
9 | public object GetService(Type serviceType) => serviceType == typeof(CurlGeneratorHttpMessageHandler) ? _service : null;
10 | }
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Fakes/FakeHttpMessageHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Fakes;
4 |
5 | public class FakeHttpMessageHandler : HttpMessageHandler
6 | {
7 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
8 | {
9 | return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/HttpClientToCurl.Sample.InSpecific.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/HttpClientToCurl.Sample.InGlobal.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/Program.cs:
--------------------------------------------------------------------------------
1 | using static HttpClientToCurl.Extensions.ServiceCollectionExtensions;
2 |
3 | var builder = WebApplication.CreateBuilder(args);
4 | builder.Services.AddControllers();
5 |
6 | builder.Services.AddAllHttpClientToCurl(builder.Configuration);
7 | builder.Services.AddHttpClient();
8 |
9 | var app = builder.Build();
10 |
11 | app.UseHttpsRedirection();
12 | app.UseAuthorization();
13 | app.MapControllers();
14 | app.Run();
15 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InFile/HttpClientToCurl.Sample.InFile.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InConsole/HttpClientToCurl.Sample.InConsole.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Fakes/FakeOptionsMonitor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Fakes;
4 |
5 | public class FakeOptionsMonitor(T value) : IOptionsMonitor where T : class
6 | {
7 | public T CurrentValue { get; } = value;
8 | public T Get(string? name) => CurrentValue;
9 | public IDisposable OnChange(Action listener) => new Disposable();
10 | private sealed class Disposable : IDisposable { public void Dispose() { } }
11 | }
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/Program.cs:
--------------------------------------------------------------------------------
1 | using static HttpClientToCurl.Extensions.ServiceCollectionExtensions;
2 |
3 | var builder = WebApplication.CreateBuilder(args);
4 | builder.Services.AddControllers();
5 |
6 | builder.Services.AddHttpClientToCurl(builder.Configuration);
7 | builder.Services.AddHttpClient("my-client1", showCurl: true);
8 | builder.Services.AddHttpClient("my-client2");
9 |
10 | var app = builder.Build();
11 |
12 | app.UseHttpsRedirection();
13 | app.UseAuthorization();
14 | app.MapControllers();
15 | app.Run();
16 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/Common/BaseBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using HttpClientToCurl.Builder.Interface;
3 | using HttpClientToCurl.Config;
4 |
5 | namespace HttpClientToCurl.Builder.Concrete.Common;
6 |
7 | public abstract class BaseBuilder : IBuilder
8 | {
9 | protected readonly StringBuilder _stringBuilder = new();
10 |
11 | public abstract string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config);
12 |
13 | public abstract string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config);
14 | }
15 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InString/HttpClientToCurl.Sample.InString.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/HttpMessageHandlers/HttpMessageHandlerAppender.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Http;
3 |
4 | namespace HttpClientToCurl.HttpMessageHandlers;
5 |
6 | public class HttpMessageHandlerAppender(IServiceProvider serviceProvider) : IHttpMessageHandlerBuilderFilter
7 | {
8 | public Action Configure(Action next) => builder =>
9 | {
10 | next(builder);
11 | var handler = serviceProvider.GetRequiredService();
12 | builder.AdditionalHandlers.Add(handler);
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/pre-push:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | LC_ALL=C
3 |
4 | local_branch="$(git rev-parse --abbrev-ref HEAD)"
5 |
6 | echo -e "\n"
7 | echo -e "->Your branch name is: ($local_branch)"
8 |
9 | valid_branch_regex="^(main|develop|dev|master)+|((hot|bug)fix|refactor|optimize|feature|document)+(\/HCG-)+([0-9]{1,5})$"
10 |
11 | if [[ ! $local_branch =~ $valid_branch_regex ]]
12 | then
13 | echo -e "->Branch name must adhere to this contract: $valid_branch_regex.
14 | ->Your commit will not be pushed to the repository. You must rename your branch to a valid name and then try again."
15 | exit 1
16 | fi
17 |
18 | echo -e "->Branch name verified "
19 | echo -e "\n"
20 | exit 0
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v2
18 | with:
19 | dotnet-version: 9.0.x
20 | - name: Restore dependencies
21 | run: dotnet restore
22 | working-directory: ./
23 | - name: Build
24 | run: dotnet build --no-restore
25 | working-directory: ./
26 | - name: Test
27 | run: dotnet test --no-build --verbosity normal
28 | working-directory: ./
29 |
--------------------------------------------------------------------------------
/Issue_Template.md:
--------------------------------------------------------------------------------
1 | # Description
2 | Provide a clear and concise description of the issue you are experiencing.
3 |
4 | # Steps to Reproduce
5 | 1. Go to '...'
6 | 2. Click on '....'
7 | 3. Scroll down to '....'
8 | 4. See error
9 |
10 | # Expected Behavior
11 | Describe what you expected to happen.
12 |
13 | # Actual Behavior
14 | Describe the actual behavior you observed.
15 |
16 | # Screenshots
17 | If applicable, add screenshots to help explain your problem.
18 |
19 | # Environment
20 | . IDE: [e.g. Rider, Vs Code, Visual Studio]
21 | . OS: [e.g. Windows 11, Ubuntu 22.04, Debian 11 ]
22 | . DOTNET_VERSION: [e.g. 3.0, 5.0, 8.0]
23 | . NUGET_VERSION: [e.g. 2.0.6]
24 |
25 | # Additional Context
26 | Add any other context about the problem here.
--------------------------------------------------------------------------------
/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | exists=0
4 | echo "do a check for .cs files in change set"
5 | while read status file; do
6 | if [ "${file: -3}" == ".cs" ] ; then
7 | exists=1
8 | echo "find .cs file"
9 | break
10 | fi
11 | done <<<$(git diff --cached --name-status)
12 |
13 | echo $exists
14 | if [[ $exists -eq 0 ]] ; then
15 | exit 0
16 | else
17 | echo "exists .cs file, so build the project"
18 | fi
19 |
20 | echo "dotnet build"
21 | dotnet clean; dotnet build
22 | rc=$?
23 |
24 | if [[ $rc != 0 ]] ; then
25 | echo "Build failed"
26 | exit $rc
27 | fi
28 |
29 | echo "dotnet test"
30 | dotnet test
31 |
32 | rc=$?
33 |
34 | if [[ $rc != 0 ]] ; then
35 | echo "Tests failed"
36 | exit $rc
37 | fi
38 |
39 | exit 0
40 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "http": {
5 | "commandName": "Project",
6 | "dotnetRunMessages": true,
7 | "launchBrowser": false,
8 | "applicationUrl": "http://localhost:5272",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | },
13 | "https": {
14 | "commandName": "Project",
15 | "dotnetRunMessages": true,
16 | "launchBrowser": false,
17 | "applicationUrl": "https://localhost:7038;http://localhost:5272",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "http": {
5 | "commandName": "Project",
6 | "dotnetRunMessages": true,
7 | "launchBrowser": false,
8 | "applicationUrl": "http://localhost:5062",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | },
13 | "https": {
14 | "commandName": "Project",
15 | "dotnetRunMessages": true,
16 | "launchBrowser": false,
17 | "applicationUrl": "https://localhost:7001;http://localhost:5062",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Fakes/FakeLogger.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Fakes;
4 |
5 | public class FakeLogger : ILogger
6 | {
7 | public List<(LogLevel Level, string Message)> LoggedMessages { get; } = [];
8 |
9 | public IDisposable? BeginScope(TState state) where TState : notnull => null;
10 |
11 | public bool IsEnabled(LogLevel logLevel) => true;
12 |
13 | public void Log(
14 | LogLevel logLevel,
15 | EventId eventId,
16 | TState state,
17 | Exception? exception,
18 | Func formatter)
19 | {
20 | var message = formatter(state, exception);
21 | LoggedMessages.Add((logLevel, message));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*",
9 | "HttpClientToCurl": {
10 | "Enable": true,
11 |
12 | "ShowOnConsole": {
13 | "TurnOn": true, //CAUTION: It will be applied when Enable is 'true'
14 | "NeedAddDefaultHeaders": true,
15 | "EnableCompression": false,
16 | "EnableCodeBeautification": true
17 | },
18 |
19 | "SaveToFile": {
20 | "TurnOn": true, //CAUTION: It will be applied when Enable is 'true'
21 | "NeedAddDefaultHeaders": true,
22 | "EnableCompression": false,
23 | "Filename": "curl_commands",
24 | "Path": "C:\\Users\\Public"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*",
9 | "HttpClientToCurl": {
10 | "Enable": true,
11 |
12 | "ShowOnConsole": {
13 | "TurnOn": true, //CAUTION: It will be applied when Enable is 'true'
14 | "NeedAddDefaultHeaders": true,
15 | "EnableCompression": false,
16 | "EnableCodeBeautification": true
17 | },
18 |
19 | "SaveToFile": {
20 | "TurnOn": true, //CAUTION: It will be applied when Enable is 'true'
21 | "NeedAddDefaultHeaders": true,
22 | "EnableCompression": false,
23 | "Filename": "curl_commands",
24 | "Path": "C:\\Users\\Public"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | netstansard2.1
8 | enable
9 | annotations
10 | 1701;1702;1591
11 | true
12 | true
13 | Linux
14 |
15 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Builders/HttpMessageHandlerBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Builders;
4 |
5 | public class HttpMessageHandlerBuilder : Microsoft.Extensions.Http.HttpMessageHandlerBuilder
6 | {
7 | private readonly IList _additional = [];
8 | public override string Name { get; set; }
9 | public override HttpMessageHandler PrimaryHandler { get; set; }
10 | public override IList AdditionalHandlers => _additional;
11 | public override IServiceProvider Services => new ServiceCollection().BuildServiceProvider();
12 | public override HttpMessageHandler Build() => PrimaryHandler;
13 |
14 | public HttpMessageHandlerBuilder()
15 | {
16 | Name = "test";
17 | PrimaryHandler = new HttpClientHandler();
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/HttpMessageHandlerTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/HttpMessageHandlerAppenderTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using HttpClientToCurl.Config;
3 | using HttpClientToCurl.HttpMessageHandlers;
4 | using HttpMessageHandlerTest.UnitTest.Builders;
5 | using HttpMessageHandlerTest.UnitTest.Fakes;
6 |
7 | namespace HttpMessageHandlerTest.UnitTest;
8 |
9 | public class HttpMessageHandlerAppenderTests
10 | {
11 | [Fact]
12 | public void HttpMessageHandlerAppender_Adds_Handler_To_Builder()
13 | {
14 | // Arrange
15 | var config = new CompositConfig { Enable = false };
16 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config));
17 | var sp = new FakeServiceProvider(handler);
18 | var appender = new HttpMessageHandlerAppender(sp);
19 |
20 | var builder = new HttpMessageHandlerBuilder();
21 |
22 | // Act
23 | var configure = appender.Configure(next => { });
24 | configure(builder);
25 |
26 | // Assert
27 | builder.AdditionalHandlers.Should().ContainSingle()
28 | .Which.Should().Be(handler);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Amin Golmahalle
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/Builders/CompositConfigBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Config;
2 |
3 | namespace HttpMessageHandlerTest.UnitTest.Builders;
4 |
5 | public class CompositConfigBuilder
6 | {
7 | private readonly CompositConfig _config;
8 | public CompositConfigBuilder()
9 | {
10 | _config = new CompositConfig();
11 | }
12 |
13 | public CompositConfigBuilder SetEnable(bool value)
14 | {
15 | _config.Enable = value;
16 | return this;
17 | }
18 |
19 | public CompositConfigBuilder SetShowOnConsole(ConsoleConfig? consoleConfig)
20 | {
21 | _config.ShowOnConsole = consoleConfig;
22 | return this;
23 | }
24 |
25 | public CompositConfigBuilder SetSaveToFile(FileConfig? fileConfig)
26 | {
27 | _config.SaveToFile = fileConfig;
28 | return this;
29 | }
30 |
31 | public CompositConfigBuilder SetSendToLogger(LoggerConfig? loggerConfig)
32 | {
33 | _config.SendToLogger = loggerConfig;
34 | return this;
35 | }
36 |
37 | public CompositConfig Build()
38 | {
39 | return _config;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Config/CompositConfig.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace HttpClientToCurl.Config;
4 |
5 | public sealed class CompositConfig
6 | {
7 | ///
8 | /// Set true to create curl output; false to disable it. Default is true.
9 | ///
10 | public bool Enable { get; set; } = true;
11 |
12 | ///
13 | /// Set true to show curl on the console; false to disable it. Default is true.
14 | /// If Enable is set to false, it will be ignored.
15 | ///
16 | public ConsoleConfig ShowOnConsole { get; set; }
17 |
18 | ///
19 | /// Set true to save the curl file; false to disable it. Default is true.
20 | /// If Enable is set to false, it will be ignored.
21 | ///
22 | public FileConfig SaveToFile { get; set; }
23 |
24 | ///
25 | /// Set true to send curl to ; false to disable it. Default is false.
26 | /// If Enable is set to false, it will be ignored.
27 | ///
28 | public LoggerConfig SendToLogger { get; set; }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/HttpRequestMessageToCurlTest/HttpRequestMessageToCurlTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/HttpRequestMessageToCurlTest/UnitTest/MediaTypes/Json/FailedCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using HttpClientToCurl.Builder;
4 | using Xunit;
5 |
6 | namespace HttpRequestMessageToCurlTest.UnitTest.MediaTypes.Json;
7 |
8 | public class FailedCurlGeneratorTests
9 | {
10 | [Fact]
11 | public void GenerateCurl_When_HttpMethod_Is_Invalid()
12 | {
13 | // Arrange
14 | string requestBody = /*lang=json,strict*/ @"{""name"":""russel"",""requestId"":10001004,""amount"":50000}";
15 |
16 | var requestUri = "api/test";
17 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Trace, requestUri)
18 | {
19 | Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json)
20 | };
21 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
22 |
23 | var baseAddress = new Uri("http://localhost:1213/v1/");
24 |
25 | // Act - Assert
26 | Assert.Throws(() => Generator.GenerateCurl(
27 | httpRequestMessage,
28 | baseAddress,
29 | null));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/HttpClientToCurlTest/HttpClientToCurlTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/HttpClientToCurlTest/UnitTest/MediaTypes/Json/FailedCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using HttpClientToCurl.Builder;
4 | using Xunit;
5 |
6 | namespace HttpClientToCurlTest.UnitTest.MediaTypes.Json;
7 |
8 | public class FailedCurlGeneratorTests
9 | {
10 | [Fact]
11 | public void GenerateCurl_When_HttpMethod_Is_Invalid()
12 | {
13 | // Arrange
14 | string requestBody = /*lang=json,strict*/ @"{""name"":""russel"",""requestId"":10001004,""amount"":50000}";
15 |
16 | var requestUri = "api/test";
17 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Trace, requestUri)
18 | {
19 | Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json)
20 | };
21 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
22 |
23 | using var httpClient = new HttpClient();
24 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
25 |
26 | // Act - Assert
27 | Assert.Throws(() => Generator.GenerateCurl(
28 | httpClient,
29 | httpRequestMessage,
30 | null));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/HttpDeleteBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete.Common;
2 | using HttpClientToCurl.Config;
3 |
4 | namespace HttpClientToCurl.Builder.Concrete;
5 |
6 | public sealed class HttpDeleteBuilder : BaseBuilder
7 | {
8 | public override string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
9 | {
10 | return _stringBuilder
11 | .Initialize(httpRequestMessage.Method)
12 | .AddAbsoluteUrl(httpClient.BaseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
13 | .AddHeaders(httpClient, httpRequestMessage, config?.NeedAddDefaultHeaders ?? new BaseConfig().NeedAddDefaultHeaders)?
14 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
15 | }
16 |
17 | public override string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
18 | {
19 | return _stringBuilder
20 | .Initialize(httpRequestMessage.Method)
21 | .AddAbsoluteUrl(baseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
22 | .AddHeaders(httpRequestMessage)?
23 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/HttpGetBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete.Common;
2 | using HttpClientToCurl.Config;
3 |
4 | namespace HttpClientToCurl.Builder.Concrete;
5 |
6 | public sealed class HttpGetBuilder : BaseBuilder
7 | {
8 | public override string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
9 | {
10 | return _stringBuilder
11 | .Initialize(httpRequestMessage.Method)
12 | .AddAbsoluteUrl(httpClient.BaseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
13 | .AddHeaders(httpClient, httpRequestMessage, config?.NeedAddDefaultHeaders ?? new BaseConfig().NeedAddDefaultHeaders)?
14 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
15 | }
16 |
17 | public override string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
18 | {
19 | return _stringBuilder
20 | .Initialize(httpRequestMessage.Method)
21 | .AddAbsoluteUrl(baseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
22 | .AddHeaders(httpRequestMessage)?
23 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/HttpPutBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete.Common;
2 | using HttpClientToCurl.Config;
3 |
4 | namespace HttpClientToCurl.Builder.Concrete;
5 |
6 | public sealed class HttpPutBuilder : BaseBuilder
7 | {
8 | public override string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
9 | {
10 | return _stringBuilder
11 | .Initialize(httpRequestMessage.Method)
12 | .AddAbsoluteUrl(httpClient.BaseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
13 | .AddHeaders(httpClient, httpRequestMessage, config?.NeedAddDefaultHeaders ?? new BaseConfig().NeedAddDefaultHeaders)?
14 | .AddBody(httpRequestMessage.Content)?
15 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
16 | }
17 |
18 | public override string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
19 | {
20 | return _stringBuilder
21 | .Initialize(httpRequestMessage.Method)
22 | .AddAbsoluteUrl(baseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
23 | .AddHeaders(httpRequestMessage)?
24 | .AddBody(httpRequestMessage.Content)?
25 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Generator.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete;
2 | using HttpClientToCurl.Builder.Interface;
3 | using HttpClientToCurl.Config;
4 |
5 | namespace HttpClientToCurl.Builder;
6 |
7 | public static class Generator
8 | {
9 | public static string GenerateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
10 | {
11 | var builder = GetBuilder(httpRequestMessage.Method);
12 | return builder.CreateCurl(httpClient, httpRequestMessage, config);
13 | }
14 |
15 | public static string GenerateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
16 | {
17 | var builder = GetBuilder(httpRequestMessage.Method);
18 | return builder.CreateCurl(httpRequestMessage, baseAddress, config);
19 | }
20 |
21 | private static IBuilder GetBuilder(HttpMethod method)
22 | {
23 | string methodName = method.Method;
24 | return methodName switch
25 | {
26 | "GET" => new HttpGetBuilder(),
27 | "POST" => new HttpPostBuilder(),
28 | "PUT" => new HttpPutBuilder(),
29 | "PATCH" => new HttpPatchBuilder(),
30 | "DELETE" => new HttpDeleteBuilder(),
31 | _ => throw new NotSupportedException($"HTTP method {method} is not supported."),
32 | };
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/HttpPatchBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete.Common;
2 | using HttpClientToCurl.Config;
3 |
4 | namespace HttpClientToCurl.Builder.Concrete;
5 |
6 | public sealed class HttpPatchBuilder : BaseBuilder
7 | {
8 | public override string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
9 | {
10 | return _stringBuilder
11 | .Initialize(httpRequestMessage.Method)
12 | .AddAbsoluteUrl(httpClient.BaseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
13 | .AddHeaders(httpClient, httpRequestMessage, config?.NeedAddDefaultHeaders ?? new BaseConfig().NeedAddDefaultHeaders)?
14 | .AddBody(httpRequestMessage.Content)?
15 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
16 | }
17 |
18 | public override string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
19 | {
20 | return _stringBuilder
21 | .Initialize(httpRequestMessage.Method)
22 | .AddAbsoluteUrl(baseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
23 | .AddHeaders(httpRequestMessage)?
24 | .AddBody(httpRequestMessage.Content)?
25 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/HttpPostBuilder.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder.Concrete.Common;
2 | using HttpClientToCurl.Config;
3 |
4 | namespace HttpClientToCurl.Builder.Concrete;
5 |
6 | public sealed class HttpPostBuilder : BaseBuilder
7 | {
8 | public override string CreateCurl(HttpClient httpClient, HttpRequestMessage httpRequestMessage, BaseConfig config)
9 | {
10 | return _stringBuilder
11 | .Initialize(httpRequestMessage.Method)
12 | .AddAbsoluteUrl(httpClient.BaseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
13 | .AddHeaders(httpClient, httpRequestMessage, config?.NeedAddDefaultHeaders ?? new BaseConfig().NeedAddDefaultHeaders)?
14 | .AddBody(httpRequestMessage.Content)?
15 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
16 | }
17 |
18 | public override string CreateCurl(HttpRequestMessage httpRequestMessage, Uri baseAddress, BaseConfig config)
19 | {
20 | return _stringBuilder
21 | .Initialize(httpRequestMessage.Method)
22 | .AddAbsoluteUrl(baseAddress?.AbsoluteUri, httpRequestMessage.RequestUri)
23 | .AddHeaders(httpRequestMessage)?
24 | .AddBody(httpRequestMessage.Content)?
25 | .Finalize(config?.EnableCompression ?? new BaseConfig().EnableCompression);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: .NET Release
2 | on:
3 | push:
4 | tags:
5 | - "v[0-9]+.[0-9]+.[0-9]+"
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | timeout-minutes: 15
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v3
13 | - name: Verify commit exists in origin/master
14 | run: |
15 | git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
16 | git branch --remote --contains | grep origin/master
17 | - name: Set VERSION variable from tag
18 | run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
19 | working-directory: src/HttpClientToCurl
20 | - name: Build
21 | run: dotnet build --configuration Release /p:Version=${VERSION}
22 | working-directory: src/HttpClientToCurl
23 | - name: Test
24 | run: dotnet test --configuration Release /p:Version=${VERSION} --no-build
25 | working-directory: src/HttpClientToCurl
26 | - name: Pack
27 | run: dotnet pack --configuration Release /p:Version=${VERSION} --no-build --output .
28 | working-directory: src/HttpClientToCurl
29 | - name: Push
30 | run: dotnet nuget push HttpClientToCurl.${VERSION}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${GITHUB_TOKEN}
31 | working-directory: src/HttpClientToCurl
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.NUGET_API_KEY }}
--------------------------------------------------------------------------------
/src/HttpClientToCurl/HttpClientToCurl.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Amin Golmahalleh
5 | 2.0.9
6 | 2.0.9
7 | netstandard2.1
8 | enable
9 | disable
10 | latest
11 | README.md
12 | This extension will help you to see whatever is set in **HttpClient** in the form of a curl script.
13 | package json extension csharp dotnet curl aspnetcore nuget xml dotnetcore httpclient postman dotnet-core aspnet-core asp-net-core asp-net dotnet-standard nuget-package asp-net-core-web-api httpclients
14 | https://github.com/amingolmahalle/HttpClientToCurlGenerator
15 | https://github.com/amingolmahalle/HttpClientToCurlGenerator
16 | git
17 | MIT
18 | True
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.lutignore:
--------------------------------------------------------------------------------
1 | ## The .lutignore file is used by Live Unit Testing to ignore Visual Studio temporary files, build results,
2 | ## and files generated by popular Visual Studio add-ons when creating a private copy of the source tree that
3 | ## Live Unit Testing uses for its build.
4 | ##
5 | ## This file has same format as git's .gitignore file (https://git-scm.com/docs/gitignore). In fact, in the
6 | ## case where a .lutignore file is not found, but a .gitignore file is found, Live Unit Testing will use the
7 | ## .gitignore file directly for the above purpose.
8 |
9 | # User-specific files
10 | *.suo
11 | *.user
12 | *.userprefs
13 | *.sln.docstates
14 | .vs/
15 | .vscode/
16 | .packages/
17 | .dotnet/
18 | .tools/
19 | .idea/
20 |
21 | # Build results
22 | [Dd]ebug/
23 | [Rr]elease/
24 | [Bb]inaries/
25 | [Bb]in/
26 | [Oo]bj/
27 | x64/
28 | TestResults/
29 |
30 | # Debug artifacts
31 | launchSettings.json
32 |
33 | # Click-Once directory
34 | publish/
35 |
36 | # Publish Web Output
37 | *.Publish.xml
38 |
39 | # NuGet
40 | packages/
41 | [Nn]u[Gg]et.exe
42 | *-packages.config
43 | *.nuget.props
44 | *.nuget.targets
45 | project.lock.json
46 | msbuild.binlog
47 | *.project.lock.json
48 |
49 | # Miscellaneous
50 | *_i.c
51 | *_p.c
52 | *.ilk
53 | *.meta
54 | *.obj
55 | *.pch
56 | *.pdb
57 | *.pgc
58 | *.pgd
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.wrn
67 | *.vspscc
68 | *.vssscc
69 | .builds
70 | *.pidb
71 | *.scc
72 | sql/
73 | *.Cache
74 | ClientBin/
75 | [Ss]tyle[Cc]op.*
76 | ~$*
77 | *~
78 | *.dbmdl
79 | *.[Pp]ublish.xml
80 | *.pfx
81 | *.publishsettings
82 |
83 | # Cache and temp files
84 | ipch/
85 | *.aps
86 | *.ncb
87 | *.opensdf
88 | *.sdf
89 | *.cachefile
90 | *.VC.opendb
91 | *.VC.db
92 | AppPackages/
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings
96 | $RECYCLE.BIN/
97 | .DS_Store
98 | *wpftmp.*
99 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Extensions/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Config;
2 | using HttpClientToCurl.HttpMessageHandlers;
3 | using Microsoft.Extensions.Configuration;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Extensions.Http;
6 |
7 | namespace HttpClientToCurl.Extensions;
8 |
9 | public static class ServiceCollectionExtensions
10 | {
11 | ///
12 | /// Generating curl script for all HTTP requests.
13 | /// By default, show it in the IDE console.
14 | ///
15 | public static void AddAllHttpClientToCurl(
16 | this IServiceCollection services,
17 | IConfiguration configuration)
18 | {
19 | AddServices(services, configuration);
20 | services.Add(ServiceDescriptor.Transient());
21 | }
22 |
23 | ///
24 | /// Generating curl script for specific http client
25 | ///
26 | ///
27 | ///
28 | public static void AddHttpClientToCurl(
29 | this IServiceCollection services,
30 | IConfiguration configuration)
31 | {
32 | AddServices(services, configuration);
33 | }
34 |
35 | public static IHttpClientBuilder AddHttpClient(this IServiceCollection services, string name, bool showCurl = false)
36 | {
37 | var httpClientBuilder = HttpClientFactoryServiceCollectionExtensions.AddHttpClient(services, name);
38 |
39 | if (showCurl)
40 | {
41 | httpClientBuilder.AddHttpMessageHandler();
42 | }
43 |
44 | return httpClientBuilder;
45 | }
46 |
47 | private static void AddServices(IServiceCollection services, IConfiguration configuration)
48 | {
49 | services.Configure(configuration.GetSection("HttpClientToCurl"));
50 | services.AddTransient();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InGlobal/Controllers/MyController.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | namespace HttpClientToCurl.Sample.InGlobal.Controllers;
5 |
6 | [ApiController]
7 | [Route("[controller]")]
8 | public class MyController(HttpClient httpClient) : ControllerBase
9 | {
10 | private readonly HttpClient _httpClient = httpClient;
11 |
12 | [HttpGet]
13 | public async Task Send()
14 | {
15 | string apiUrl = "https://jsonplaceholder.typicode.com/posts";
16 |
17 | try
18 | {
19 | // Create a sample JSON payload
20 | string jsonPayload =
21 | $"{{\"title\":\"New Post\",\"body\":\"This is the body of the new post\",\"userId\":1}}";
22 |
23 | // Create HttpRequestMessage with the POST verb
24 | HttpRequestMessage request = new(HttpMethod.Post, apiUrl);
25 |
26 | // Set up the request headers
27 | request.Headers.Add("Authorization", "Bearer YourAccessToken"); // Add any necessary headers
28 |
29 | // Set the request content with the JSON payload
30 | request.Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
31 |
32 | // Log the curl command for debugging or testing.
33 | // This generates a curl command that can be imported into Postman.
34 | // Use it to check and compare against all the requirements.
35 |
36 | // Send the request
37 | HttpResponseMessage response = await _httpClient.SendAsync(request);
38 |
39 | // Check if the request was successful (status code 200-299)
40 | if (response.IsSuccessStatusCode)
41 | {
42 | // Read and print the response content as a string
43 | string responseBody = await response.Content.ReadAsStringAsync();
44 | Console.WriteLine("Response from the API:\n" + responseBody);
45 | }
46 | else
47 | {
48 | Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
49 | }
50 | }
51 | catch (Exception ex)
52 | {
53 | Console.WriteLine($"Exception: {ex.Message}");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Extensions/HttpRequestMessageExtensions.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Builder;
2 | using HttpClientToCurl.Config;
3 | using HttpClientToCurl.Utility;
4 |
5 | namespace HttpClientToCurl.Extensions;
6 |
7 | public static class HttpRequestMessageExtensions
8 | {
9 | #region :: EXTENSIONS ::
10 |
11 | #region : Put in a variable :
12 |
13 | public static string GenerateCurlInString(this HttpRequestMessage httpRequestMessage, Uri baseAddress, Action config = null)
14 | {
15 | var stringConfig = new StringConfig();
16 | config?.Invoke(stringConfig);
17 |
18 | if (!stringConfig.TurnOn)
19 | {
20 | return string.Empty;
21 | }
22 |
23 | string script = Generator.GenerateCurl(
24 | httpRequestMessage,
25 | baseAddress,
26 | stringConfig);
27 |
28 | return script;
29 | }
30 |
31 | #endregion : Put in a variable :
32 |
33 | #region : Show in the console :
34 |
35 | public static void GenerateCurlInConsole(this HttpRequestMessage httpRequestMessage, Uri baseAddress, Action config = null)
36 | {
37 | var consoleConfig = new ConsoleConfig();
38 | config?.Invoke(consoleConfig);
39 |
40 | if (!consoleConfig.TurnOn)
41 | {
42 | return;
43 | }
44 |
45 | string script = Generator.GenerateCurl(httpRequestMessage, baseAddress, consoleConfig);
46 |
47 | Helpers.WriteInConsole(script, consoleConfig.EnableCodeBeautification, httpRequestMessage.Method);
48 | }
49 |
50 | #endregion : Print in the console :
51 |
52 | #region : Write in a file :
53 |
54 | public static void GenerateCurlInFile(this HttpRequestMessage httpRequestMessage, Uri baseAddress, Action config = null)
55 | {
56 | var fileConfig = new FileConfig();
57 | config?.Invoke(fileConfig);
58 |
59 | if (!fileConfig.TurnOn)
60 | {
61 | return;
62 | }
63 |
64 | string script = Generator.GenerateCurl(httpRequestMessage, baseAddress, fileConfig);
65 |
66 | Helpers.WriteInFile(script, fileConfig.Filename, fileConfig.Path);
67 | }
68 |
69 | #endregion : Write in a file :
70 |
71 | #endregion :: EXTENSIONS ::
72 | }
73 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InSpecific/Controllers/MyController.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | namespace HttpClientToCurl.Sample.InSpecific.Controllers;
5 |
6 | [ApiController]
7 | [Route("[controller]")]
8 | public class MyController(IHttpClientFactory httpClientFactory) : ControllerBase
9 | {
10 | private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
11 |
12 | [HttpGet("send-and-show-curl")]
13 | public async Task SendAndShowCurl()
14 | {
15 | await SendRemoteRequest("my-client1");
16 | }
17 |
18 | [HttpGet("send")]
19 | public async Task Send()
20 | {
21 | await SendRemoteRequest("my-client2");
22 | }
23 |
24 | private async Task SendRemoteRequest(string httpClientName)
25 | {
26 | string apiUrl = "https://jsonplaceholder.typicode.com/posts";
27 |
28 | try
29 | {
30 | // Create a sample JSON payload
31 | string jsonPayload =
32 | $"{{\"title\":\"New Post\",\"body\":\"This is the body of the new post\",\"userId\":1}}";
33 |
34 | // Create HttpRequestMessage with the POST verb
35 | HttpRequestMessage request = new(HttpMethod.Post, apiUrl);
36 |
37 | // Set up the request headers
38 | request.Headers.Add("Authorization", "Bearer YourAccessToken"); // Add any necessary headers
39 |
40 | // Set the request content with the JSON payload
41 | request.Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
42 |
43 | // Log the curl command for debugging or testing.
44 | // This generates a curl command that can be imported into Postman.
45 | // Use it to check and compare against all the requirements.
46 |
47 | // Send the request
48 | HttpResponseMessage response = await _httpClientFactory.CreateClient(httpClientName).SendAsync(request);
49 |
50 | // Check if the request was successful (status code 200-299)
51 | if (response.IsSuccessStatusCode)
52 | {
53 | // Read and print the response content as a string
54 | string responseBody = await response.Content.ReadAsStringAsync();
55 | Console.WriteLine("Response from the API:\n" + responseBody);
56 | }
57 | else
58 | {
59 | Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
60 | }
61 | }
62 | catch (Exception ex)
63 | {
64 | Console.WriteLine($"Exception: {ex.Message}");
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/HttpMessageHandlers/CurlGeneratorHttpMessageHandler.cs:
--------------------------------------------------------------------------------
1 | using HttpClientToCurl.Config;
2 | using HttpClientToCurl.Extensions;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 |
6 | namespace HttpClientToCurl.HttpMessageHandlers;
7 |
8 | public class CurlGeneratorHttpMessageHandler(
9 | IOptionsMonitor monitorConfig,
10 | ILogger logger = null) : DelegatingHandler
11 | {
12 | private readonly IOptionsMonitor _monitorConfig = monitorConfig;
13 | private readonly ILogger _logger = logger;
14 |
15 | protected override Task SendAsync(
16 | HttpRequestMessage httpRequestMessage,
17 | CancellationToken cancellationToken)
18 | {
19 | var config = _monitorConfig.CurrentValue;
20 | if (config.Enable)
21 | {
22 | if (config.ShowOnConsole?.TurnOn ?? false)
23 | {
24 | httpRequestMessage.GenerateCurlInConsole(httpRequestMessage.RequestUri, consoleConfig =>
25 | {
26 | consoleConfig.TurnOn = true;
27 | consoleConfig.EnableCodeBeautification = config.ShowOnConsole.EnableCodeBeautification;
28 | consoleConfig.EnableCompression = config.ShowOnConsole.EnableCompression;
29 | consoleConfig.NeedAddDefaultHeaders = config.ShowOnConsole.NeedAddDefaultHeaders;
30 | });
31 | }
32 |
33 | if (config.SaveToFile?.TurnOn ?? false)
34 | {
35 | httpRequestMessage.GenerateCurlInFile(httpRequestMessage.RequestUri, fileConfig =>
36 | {
37 | fileConfig.TurnOn = true;
38 | fileConfig.EnableCompression = config.SaveToFile.EnableCompression;
39 | fileConfig.NeedAddDefaultHeaders = config.SaveToFile.NeedAddDefaultHeaders;
40 | fileConfig.Path = config.SaveToFile.Path;
41 | fileConfig.Filename = config.SaveToFile.Filename;
42 | });
43 | }
44 |
45 | if (config.SendToLogger?.TurnOn ?? false)
46 | {
47 | if (_logger != null)
48 | {
49 | var curl = httpRequestMessage.GenerateCurlInString(httpRequestMessage.RequestUri, stringConfig =>
50 | {
51 | stringConfig.TurnOn = true;
52 | stringConfig.EnableCompression = config.SendToLogger.EnableCompression;
53 | stringConfig.NeedAddDefaultHeaders = config.SendToLogger.NeedAddDefaultHeaders;
54 | });
55 |
56 | _logger.Log(config.SendToLogger.LogLevel, curl);
57 | }
58 | }
59 | }
60 |
61 | var response = base.SendAsync(httpRequestMessage, cancellationToken);
62 | return response;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/HttpRequestMessageToCurlTest/UnitTest/MediaTypes/Xml/SuccessCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using FluentAssertions;
4 | using HttpClientToCurl.Builder;
5 | using Xunit;
6 |
7 | namespace HttpRequestMessageToCurlTest.UnitTest.MediaTypes.Xml;
8 |
9 | public class SuccessCurlGeneratorTests
10 | {
11 | [Fact]
12 | public void Get_Curl_Script_For_PostMethod()
13 | {
14 | // Arrange
15 | string requestBody = @"
16 |
17 | 12
18 | Jason
19 | 10001024
20 | 240000
21 | ";
22 |
23 | var requestUri = "api/test";
24 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Text.Xml) };
25 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
26 |
27 | var baseAddress = new Uri("http://localhost:1213/v1/");
28 |
29 | // Act
30 | string script = Generator.GenerateCurl(
31 | httpRequestMessage,
32 | baseAddress,
33 | null);
34 |
35 | // Assert
36 | script.Should().NotBeNullOrEmpty();
37 | script.Should().StartWith("curl -X POST");
38 | script.Trim().Should().BeEquivalentTo(
39 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: text/xml; charset=utf-8' -d '
40 |
41 | 12
42 | Jason
43 | 10001024
44 | 240000
45 | '");
46 | }
47 |
48 | [Fact]
49 | public void Get_Error_Message_When_Input_XML_Is_Invalid_For_PostMethod()
50 | {
51 | // Arrange
52 | string requestBody = @"
53 |
54 | 12
55 | Jason
56 | 10001024
57 | 240000
58 | ";
59 |
60 | var requestUri = "api/test";
61 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Text.Xml) };
62 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
63 |
64 | var baseAddress = new Uri("http://localhost:1213/v1/");
65 |
66 | // Act
67 | string script = Generator.GenerateCurl(
68 | httpRequestMessage,
69 | baseAddress,
70 | null);
71 |
72 | // Assert
73 | script.Should().NotBeNull();
74 | script.Should().NotBeEmpty();
75 | script.Should().StartWith("curl -X POST");
76 | script.Trim().Should().BeEquivalentTo(
77 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: text/xml; charset=utf-8' -d '
78 |
79 | 12
80 | Jason
81 | 10001024
82 | 240000
83 | '");
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tests/HttpClientToCurlTest/UnitTest/MediaTypes/Xml/SuccessCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using FluentAssertions;
4 | using HttpClientToCurl.Builder;
5 | using Xunit;
6 |
7 | namespace HttpClientToCurlTest.UnitTest.MediaTypes.Xml;
8 |
9 | public class SuccessCurlGeneratorTests
10 | {
11 | [Fact]
12 | public void Get_Curl_Script_For_PostMethod()
13 | {
14 | // Arrange
15 | string requestBody = @"
16 |
17 | 12
18 | Jason
19 | 10001024
20 | 240000
21 | ";
22 |
23 | var requestUri = "api/test";
24 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Text.Xml) };
25 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
26 |
27 | using var httpClient = new HttpClient();
28 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
29 |
30 | // Act
31 | string script = Generator.GenerateCurl(
32 | httpClient,
33 | httpRequestMessage,
34 | null);
35 |
36 | // Assert
37 | script.Should().NotBeNullOrEmpty();
38 | script.Should().StartWith("curl -X POST");
39 | script.Trim().Should().BeEquivalentTo(
40 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: text/xml; charset=utf-8' -d '
41 |
42 | 12
43 | Jason
44 | 10001024
45 | 240000
46 | '");
47 | }
48 |
49 | [Fact]
50 | public void Get_Error_Message_When_Input_XML_Is_Invalid_For_PostMethod()
51 | {
52 | // Arrange
53 | string requestBody = @"
54 |
55 | 12
56 | Jason
57 | 10001024
58 | 240000
59 | ";
60 |
61 | var requestUri = "api/test";
62 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Text.Xml) };
63 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
64 |
65 | using var httpClient = new HttpClient();
66 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
67 |
68 | // Act
69 | string script = Generator.GenerateCurl(
70 | httpClient,
71 | httpRequestMessage,
72 | null);
73 |
74 | // Assert
75 | script.Should().NotBeNull();
76 | script.Should().NotBeEmpty();
77 | script.Should().StartWith("curl -X POST");
78 | script.Trim().Should().BeEquivalentTo(
79 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: text/xml; charset=utf-8' -d '
80 |
81 | 12
82 | Jason
83 | 10001024
84 | 240000
85 | '");
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InString/ApiCaller.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using HttpClientToCurl.Extensions;
3 |
4 | namespace HttpClientToCurl.Sample.InString;
5 |
6 | public static class ApiCaller
7 | {
8 | // Create an instance of HttpClient
9 | private static readonly HttpClient Client = new();
10 | private const string ApiUrl = "https://jsonplaceholder.typicode.com/posts";
11 |
12 | public static async Task MakeApiCall()
13 | {
14 | try
15 | {
16 | // Create a sample JSON payload
17 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
18 |
19 | // Create HttpRequestMessage with the POST verb
20 | HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, ApiUrl);
21 |
22 | // Set up the request headers
23 | httpRequestMessage.Headers.Add("Authorization", "Bearer YourAccessToken"); // Add any necessary headers
24 |
25 | // Set the request content with the JSON payload
26 | httpRequestMessage.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
27 |
28 | /* Generate a curl command and set it to a string variable for debugging or testing.
29 | This command can be imported into Postman for checking and comparing against all the requirements. */
30 |
31 | // *** First Scenario ***
32 | GenerateCurlByHttpClient(httpRequestMessage);
33 | // *** Second Scenario ***
34 | GenerateCurlByHttpRequestMessage(httpRequestMessage);
35 |
36 | // Send the request
37 | HttpResponseMessage response = await Client.SendAsync(httpRequestMessage);
38 |
39 | // Check if the request was successful (status code 200-299)
40 | if (response.IsSuccessStatusCode)
41 | {
42 | // Read and print the response content as a string
43 | string responseBody = await response.Content.ReadAsStringAsync();
44 | Console.WriteLine("Response from the API:\n" + responseBody);
45 | }
46 | else
47 | {
48 | Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
49 | }
50 | }
51 | catch (Exception ex)
52 | {
53 | Console.WriteLine($"Exception: {ex.Message}");
54 | }
55 | }
56 |
57 | #region << Private Methods >>
58 |
59 | private static void GenerateCurlByHttpClient(HttpRequestMessage httpRequestMessage)
60 | {
61 | // config is optional
62 | string curlResult = Client.GenerateCurlInString(httpRequestMessage, config =>
63 | {
64 | // Customize string variable configuration if needed
65 | config.TurnOn = true; // Enable generating curl command to string variable
66 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
67 | });
68 |
69 | Console.WriteLine("* Generate Curl By HttpClient:");
70 | Console.WriteLine(curlResult);
71 | Console.WriteLine();
72 | }
73 |
74 | private static void GenerateCurlByHttpRequestMessage(HttpRequestMessage httpRequestMessage)
75 | {
76 | // config is optional
77 | string curlResult = httpRequestMessage.GenerateCurlInString(new Uri(ApiUrl), config =>
78 | {
79 | // Customize string variable configuration if needed
80 | config.TurnOn = true; // Enable generating curl command to string variable
81 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
82 | });
83 |
84 | Console.WriteLine("* Generate Curl By HttpRequestMessage:");
85 | Console.WriteLine(curlResult);
86 | Console.WriteLine();
87 | }
88 |
89 | #endregion << Private Methods >>
90 | }
91 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InConsole/ApiCaller.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using HttpClientToCurl.Extensions;
3 |
4 | namespace HttpClientToCurl.Sample.InConsole;
5 |
6 | public static class ApiCaller
7 | {
8 | // Create an instance of HttpClient
9 | private static readonly HttpClient Client = new();
10 | private const string ApiUrl = "https://jsonplaceholder.typicode.com/posts";
11 |
12 | public static async Task MakeApiCall()
13 | {
14 | try
15 | {
16 | // Create a sample JSON payload
17 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
18 |
19 | // Create HttpRequestMessage with the POST verb
20 | HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, ApiUrl);
21 |
22 | // Set up the request headers
23 | httpRequestMessage.Headers.Add("Authorization", "Bearer YourAccessToken"); // Add any necessary headers
24 |
25 | // Set the request content with the JSON payload
26 | httpRequestMessage.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
27 |
28 | /* Generate a curl command and print it in the console for debugging or testing.
29 | This command can be imported into Postman for checking and comparing against all the requirements. */
30 |
31 | // *** First Scenario ***
32 | GenerateCurlByHttpClient(httpRequestMessage);
33 | // *** Second Scenario ***
34 | GenerateCurlByHttpRequestMessage(httpRequestMessage);
35 |
36 | // Send the request
37 | HttpResponseMessage response = await Client.SendAsync(httpRequestMessage);
38 |
39 | // Check if the request was successful (status code 200-299)
40 | if (response.IsSuccessStatusCode)
41 | {
42 | // Read and print the response content as a string
43 | string responseBody = await response.Content.ReadAsStringAsync();
44 | Console.WriteLine("Response from the API:\n" + responseBody);
45 | }
46 | else
47 | {
48 | Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
49 | }
50 | }
51 | catch (Exception ex)
52 | {
53 | Console.WriteLine($"Exception: {ex.Message}");
54 | }
55 | }
56 |
57 | #region << Private Methods >>
58 |
59 | private static void GenerateCurlByHttpClient(HttpRequestMessage httpRequestMessage)
60 | {
61 | Console.WriteLine("* Generate Curl By HttpClient:");
62 |
63 | // config is optional
64 | Client.GenerateCurlInConsole(httpRequestMessage, config =>
65 | {
66 | // Customize console configuration if needed
67 | config.TurnOn = true; // Enable generating curl command to the console
68 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
69 | config.EnableCodeBeautification = true;
70 | config.EnableCompression = false;
71 | });
72 |
73 | Console.WriteLine();
74 | }
75 |
76 | private static void GenerateCurlByHttpRequestMessage(HttpRequestMessage httpRequestMessage)
77 | {
78 | Console.WriteLine("* Generate Curl By HttpRequestMessage:");
79 |
80 | // config is optional
81 | httpRequestMessage.GenerateCurlInConsole(new Uri(ApiUrl), config =>
82 | {
83 | // Customize console configuration if needed
84 | config.TurnOn = true; // Enable generating curl command to the console
85 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
86 | config.EnableCodeBeautification = true;
87 | config.EnableCompression = false;
88 | });
89 |
90 | Console.WriteLine();
91 | }
92 |
93 | #endregion << Private Methods >>
94 | }
95 |
--------------------------------------------------------------------------------
/examples/HttpClientToCurl.Sample.InFile/ApiCaller.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using HttpClientToCurl.Extensions;
3 |
4 | namespace HttpClientToCurl.Sample.InFile;
5 |
6 | public static class ApiCaller
7 | {
8 | // Create an instance of HttpClient
9 | private static readonly HttpClient Client = new();
10 | private const string ApiUrl = "https://jsonplaceholder.typicode.com/posts";
11 |
12 | public static async Task MakeApiCall()
13 | {
14 | try
15 | {
16 | // Create a sample JSON payload
17 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
18 |
19 | // Create HttpRequestMessage with the POST verb
20 | HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, ApiUrl);
21 |
22 | // Set up the request headers
23 | httpRequestMessage.Headers.Add("Authorization", "Bearer YourAccessToken"); // Add any necessary headers
24 |
25 | // Set the request content with the JSON payload
26 | httpRequestMessage.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
27 |
28 | /* Generate a curl command and write it to a file for debugging or testing.
29 | This command can be imported into Postman for checking and comparing against all the requirements. */
30 |
31 | // *** First Scenario ***
32 | GenerateCurlByHttpClient(httpRequestMessage);
33 | // *** Second Scenario ***
34 | GenerateCurlByHttpRequestMessage(httpRequestMessage);
35 |
36 | // Send the request
37 | HttpResponseMessage response = await Client.SendAsync(httpRequestMessage);
38 |
39 | // Check if the request was successful (status code 200-299)
40 | if (response.IsSuccessStatusCode)
41 | {
42 | // Read and print the response content as a string
43 | string responseBody = await response.Content.ReadAsStringAsync();
44 | Console.WriteLine("Response from the API:\n" + responseBody);
45 | }
46 | else
47 | {
48 | Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
49 | }
50 | }
51 | catch (Exception ex)
52 | {
53 | Console.WriteLine($"Exception: {ex.Message}");
54 | }
55 | }
56 |
57 | #region << Private Methods >>
58 |
59 | private static void GenerateCurlByHttpClient(HttpRequestMessage httpRequestMessage)
60 | {
61 | Console.WriteLine("* Generate Curl By HttpClient:");
62 |
63 | // config is optional
64 | Client.GenerateCurlInFile(httpRequestMessage, config =>
65 | {
66 | // Customize file configuration if needed
67 | config.TurnOn = true; // Enable generating curl command to file
68 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
69 | config.Filename = "curl_commands"; // Specify the file name
70 | config.Path = @"C:\Path\To\Directory"; // Specify the directory path !!
71 | });
72 |
73 | Console.WriteLine("Done.");
74 | Console.WriteLine();
75 | }
76 |
77 | private static void GenerateCurlByHttpRequestMessage(HttpRequestMessage httpRequestMessage)
78 | {
79 | Console.WriteLine("* Generate Curl By HttpRequestMessage:");
80 |
81 | // config is optional
82 | httpRequestMessage.GenerateCurlInFile(new Uri(ApiUrl), config =>
83 | {
84 | // Customize file configuration if needed
85 | config.TurnOn = true; // Enable generating curl command to file
86 | config.NeedAddDefaultHeaders = true; // Specify if default headers should be included
87 | config.Filename = "curl_commands"; // Specify the file name
88 | config.Path = @"C:\Path\To\Directory"; // Specify the directory path !!
89 | });
90 |
91 | Console.WriteLine("Done.");
92 | Console.WriteLine();
93 | }
94 |
95 | #endregion << Private Methods >>
96 | }
97 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/ServiceCollectionExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using FluentAssertions;
3 | using HttpClientToCurl.Config;
4 | using HttpClientToCurl.Extensions;
5 | using HttpClientToCurl.HttpMessageHandlers;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Http;
8 | using Microsoft.Extensions.Options;
9 |
10 | namespace HttpMessageHandlerTest.UnitTest;
11 |
12 | public class ServiceCollectionExtensionsTests
13 | {
14 | [Fact]
15 | public void ServiceCollectionExtensions_Register_Services_For_All()
16 | {
17 | // Arrange
18 | var services = new ServiceCollection();
19 | var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
20 | .Build();
21 |
22 | // Act
23 | services.AddAllHttpClientToCurl(configuration);
24 | var provider = services.BuildServiceProvider();
25 |
26 | // Assert
27 | var filter = provider.GetService();
28 | filter.Should().NotBeNull();
29 | filter.Should().BeOfType();
30 |
31 | var handler = provider.GetService();
32 | handler.Should().NotBeNull();
33 |
34 | var options = provider.GetService>();
35 | options.Should().NotBeNull();
36 | }
37 |
38 | [Fact]
39 | public void ServiceCollectionExtensions_Register_Services_In_SpecificMode()
40 | {
41 | // Arrange
42 | var services = new ServiceCollection();
43 | var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
44 | .Build();
45 |
46 | // Act
47 | services.AddHttpClientToCurl(configuration);
48 | var provider = services.BuildServiceProvider();
49 |
50 | // Assert
51 | var filter = provider.GetService();
52 | filter.Should().BeNull();
53 |
54 | var handler = provider.GetService();
55 | handler.Should().NotBeNull();
56 |
57 | var options = provider.GetService>();
58 | options.Should().NotBeNull();
59 | }
60 |
61 | [Fact]
62 | public void ServiceCollectionExtensions_AddHttpMessageHandler_When_ShowCurl_IsEnabled()
63 | {
64 | // Arrange
65 | var services = new ServiceCollection();
66 |
67 | services.AddTransient();
68 | services.AddHttpClient("TestClient", true);
69 |
70 | var serviceProvider = services.BuildServiceProvider();
71 | var httpClientFactory = serviceProvider.GetRequiredService();
72 |
73 | // Act
74 | var httpClient = httpClientFactory.CreateClient("TestClient");
75 |
76 | // Assert
77 | var hasHandler = HasCurlGeneratorHttpMessageHandler(httpClient);
78 | hasHandler.Should().BeTrue();
79 | }
80 |
81 | [Fact]
82 | public void ServiceCollectionExtensions_AddHttpMessageHandler_When_ShowCurl_IsNotEnabled()
83 | {
84 | // Arrange
85 | var services = new ServiceCollection();
86 |
87 | services.AddTransient();
88 | services.AddHttpClient("TestClient", false);
89 |
90 | var serviceProvider = services.BuildServiceProvider();
91 | var httpClientFactory = serviceProvider.GetRequiredService();
92 |
93 | // Act
94 | var httpClient = httpClientFactory.CreateClient("TestClient");
95 |
96 | // Assert
97 | var hasHandler = HasCurlGeneratorHttpMessageHandler(httpClient);
98 | hasHandler.Should().BeFalse();
99 | }
100 |
101 | private static bool HasCurlGeneratorHttpMessageHandler(HttpClient client)
102 | {
103 | var field = typeof(HttpMessageInvoker).GetField("_handler", BindingFlags.NonPublic | BindingFlags.Instance);
104 | var handler = field?.GetValue(client);
105 |
106 | while (handler is DelegatingHandler delegatingHandler)
107 | {
108 | if (delegatingHandler.GetType() == typeof(CurlGeneratorHttpMessageHandler))
109 | {
110 | return true;
111 | }
112 | handler = delegatingHandler.InnerHandler;
113 | }
114 |
115 | return false;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Utility/Helpers.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Headers;
2 |
3 | namespace HttpClientToCurl.Utility;
4 |
5 | public static class Helpers
6 | {
7 | internal static void WriteInConsole(string script, bool enableCodeBeautification, HttpMethod httpMethod)
8 | {
9 | if (!enableCodeBeautification)
10 | {
11 | Console.WriteLine(script);
12 | }
13 | else
14 | {
15 | Console.ForegroundColor = SetColor(httpMethod);
16 | Console.WriteLine(script);
17 | Console.ResetColor();
18 | }
19 | }
20 |
21 | internal static void WriteInFile(string script, string filename, string path)
22 | {
23 | path = NormalizedPath(path);
24 | filename = NormalizedFilename(filename);
25 |
26 | string fullPath = $"{path}{Path.DirectorySeparatorChar}{filename}.curl";
27 | if (File.Exists(fullPath))
28 | {
29 | using var streamWriter = new StreamWriter(fullPath, true);
30 | streamWriter.WriteLine(script);
31 | }
32 | else
33 | {
34 | using var streamWriter = File.CreateText(fullPath);
35 | streamWriter.WriteLine(script);
36 | }
37 | }
38 |
39 | private static ConsoleColor SetColor(HttpMethod httpMethod)
40 | {
41 | ConsoleColor color;
42 |
43 | if (httpMethod == HttpMethod.Post)
44 | {
45 | color = ConsoleColor.Green;
46 | }
47 | else if (httpMethod == HttpMethod.Get)
48 | {
49 | color = ConsoleColor.Cyan;
50 | }
51 | else if (httpMethod == HttpMethod.Put)
52 | {
53 | color = ConsoleColor.Yellow;
54 | }
55 | else if (httpMethod == HttpMethod.Patch)
56 | {
57 | color = ConsoleColor.Magenta;
58 | }
59 | else if (httpMethod == HttpMethod.Delete)
60 | {
61 | color = ConsoleColor.Red;
62 | }
63 | else
64 | {
65 | color = ConsoleColor.White;
66 | }
67 |
68 | return color;
69 | }
70 |
71 | private static string NormalizedPath(string path)
72 | {
73 | string inputPath = path?.Trim();
74 | if (string.IsNullOrWhiteSpace(inputPath))
75 | {
76 | inputPath = Directory.GetCurrentDirectory();
77 | }
78 |
79 | if (inputPath.EndsWith('/'))
80 | {
81 | inputPath = inputPath[..^1];
82 | }
83 |
84 | return inputPath;
85 | }
86 |
87 | private static string NormalizedFilename(string filename)
88 | {
89 | return string.IsNullOrWhiteSpace(filename)
90 | ? DateTime.Now.Date.ToString("yyyyMMdd")
91 | : filename.Trim();
92 | }
93 |
94 | internal static HttpRequestMessage FillHttpRequestMessage(HttpMethod httpMethod, HttpRequestHeaders requestHeaders, HttpContent requestBody, Uri requestUri)
95 | {
96 | var httpRequestMessage = new HttpRequestMessage
97 | {
98 | Method = httpMethod
99 | };
100 |
101 | if (requestBody is not null)
102 | {
103 | httpRequestMessage.Content = requestBody;
104 | }
105 |
106 | if (requestHeaders is not null && requestHeaders.Any())
107 | {
108 | foreach (var header in requestHeaders)
109 | {
110 | httpRequestMessage.Headers.Add(header.Key, header.Value);
111 | }
112 | }
113 |
114 | httpRequestMessage.RequestUri = requestUri;
115 |
116 | return httpRequestMessage;
117 | }
118 |
119 | internal static HttpRequestMessage FillHttpRequestMessage(HttpMethod httpMethod, HttpRequestHeaders requestHeaders, HttpContent requestBody, string requestUri)
120 | {
121 | return FillHttpRequestMessage(httpMethod, requestHeaders, requestBody, CreateUri(requestUri));
122 | }
123 |
124 | internal static bool CheckAddressIsAbsoluteUri(Uri baseAddress)
125 | {
126 | if (baseAddress is null || !baseAddress.IsAbsoluteUri || !IsHttpUri(baseAddress))
127 | {
128 | return false;
129 | }
130 |
131 | return true;
132 | }
133 |
134 | private static bool IsHttpUri(Uri uri)
135 | {
136 | string scheme = uri.Scheme;
137 |
138 | return string.Equals("http", scheme, StringComparison.OrdinalIgnoreCase) ||
139 | string.Equals("https", scheme, StringComparison.OrdinalIgnoreCase);
140 | }
141 |
142 | public static Uri CreateUri(string uri)
143 | {
144 | return string.IsNullOrWhiteSpace(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Extensions/HttpClientExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Headers;
2 | using HttpClientToCurl.Builder;
3 | using HttpClientToCurl.Config;
4 | using HttpClientToCurl.Utility;
5 |
6 | namespace HttpClientToCurl.Extensions;
7 |
8 | public static class HttpClientExtensions
9 | {
10 | #region :: EXTENSIONS ::
11 |
12 | #region : Put in a variable :
13 |
14 | public static string GenerateCurlInString(this HttpClient httpClient, HttpRequestMessage httpRequestMessage, Action config = null)
15 | {
16 | var stringConfig = new StringConfig();
17 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, stringConfig, config);
18 |
19 | return script;
20 | }
21 |
22 | public static string GenerateCurlInString(
23 | this HttpClient httpClient,
24 | HttpMethod httpMethod,
25 | string requestUri = "",
26 | HttpRequestHeaders httpRequestHeaders = null,
27 | HttpContent httpContent = null,
28 | Action config = null)
29 | {
30 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
31 | var stringConfig = new StringConfig();
32 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, stringConfig, config);
33 |
34 | return script;
35 | }
36 |
37 | public static string GenerateCurlInString(
38 | this HttpClient httpClient,
39 | HttpMethod httpMethod,
40 | Uri requestUri,
41 | HttpRequestHeaders httpRequestHeaders = null,
42 | HttpContent httpContent = null,
43 | Action config = null)
44 | {
45 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
46 | var stringConfig = new StringConfig();
47 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, stringConfig, config);
48 |
49 | return script;
50 | }
51 |
52 | #endregion : Put in a variable :
53 |
54 | #region : Show in the console :
55 |
56 | public static void GenerateCurlInConsole(this HttpClient httpClient, HttpRequestMessage httpRequestMessage, Action config = null)
57 | {
58 | var consoleConfig = new ConsoleConfig();
59 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, consoleConfig, config);
60 |
61 | Helpers.WriteInConsole(script, consoleConfig.EnableCodeBeautification, httpRequestMessage.Method);
62 | }
63 |
64 | public static void GenerateCurlInConsole(
65 | this HttpClient httpClient,
66 | HttpMethod httpMethod,
67 | string requestUri = "",
68 | HttpRequestHeaders httpRequestHeaders = null,
69 | HttpContent httpContent = null,
70 | Action config = null)
71 | {
72 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
73 | var consoleConfig = new ConsoleConfig();
74 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, consoleConfig, config);
75 |
76 | Helpers.WriteInConsole(script, consoleConfig.EnableCodeBeautification, httpRequestMessage.Method);
77 | }
78 |
79 | public static void GenerateCurlInConsole(
80 | this HttpClient httpClient,
81 | HttpMethod httpMethod,
82 | Uri requestUri,
83 | HttpRequestHeaders httpRequestHeaders = null,
84 | HttpContent httpContent = null,
85 | Action config = null)
86 | {
87 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
88 | var consoleConfig = new ConsoleConfig();
89 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, consoleConfig, config);
90 |
91 | Helpers.WriteInConsole(script, consoleConfig.EnableCodeBeautification, httpRequestMessage.Method);
92 | }
93 |
94 | #endregion : Print in the console :
95 |
96 | #region : Write in a file :
97 |
98 | public static void GenerateCurlInFile(this HttpClient httpClient, HttpRequestMessage httpRequestMessage, Action config = null)
99 | {
100 | var fileConfig = new FileConfig();
101 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, fileConfig, config);
102 |
103 | Helpers.WriteInFile(script, fileConfig.Filename, fileConfig.Path);
104 | }
105 |
106 | public static void GenerateCurlInFile(
107 | this HttpClient httpClient,
108 | HttpMethod httpMethod,
109 | string requestUri = "",
110 | HttpRequestHeaders httpRequestHeaders = null,
111 | HttpContent httpContent = null,
112 | Action config = null)
113 | {
114 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
115 | var fileConfig = new FileConfig();
116 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, fileConfig, config);
117 |
118 | Helpers.WriteInFile(script, fileConfig.Filename, fileConfig.Path);
119 | }
120 |
121 | public static void GenerateCurlInFile(
122 | this HttpClient httpClient,
123 | HttpMethod httpMethod,
124 | Uri requestUri,
125 | HttpRequestHeaders httpRequestHeaders = null,
126 | HttpContent httpContent = null,
127 | Action config = null)
128 | {
129 | var httpRequestMessage = Helpers.FillHttpRequestMessage(httpMethod, httpRequestHeaders, httpContent, requestUri);
130 | var fileConfig = new FileConfig();
131 | var script = GenerateCurlBaseOnConfig(httpClient, httpRequestMessage, fileConfig, config);
132 |
133 | Helpers.WriteInFile(script, fileConfig.Filename, fileConfig.Path);
134 | }
135 |
136 | #endregion : Write in a file :\
137 |
138 | #region : Private methods :
139 | private static string GenerateCurlBaseOnConfig(HttpClient httpClient, HttpRequestMessage httpRequestMessage, TConfig config, Action configAction) where TConfig : BaseConfig
140 | {
141 | configAction?.Invoke(config);
142 | return config.TurnOn ? Generator.GenerateCurl(httpClient, httpRequestMessage, config) : string.Empty;
143 | }
144 |
145 | #endregion : Private methods :
146 |
147 | #endregion :: EXTENSIONS ::
148 | }
149 |
--------------------------------------------------------------------------------
/HttpClientToCurlGenerator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.7.34221.43
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClientToCurl", "src\HttpClientToCurl\HttpClientToCurl.csproj", "{18B3309D-B84C-453D-8EF7-16CA9E58F5DC}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{A8574DB9-8411-4F81-A82E-F97AD00EF8AF}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClientToCurl.Sample.InConsole", "examples\HttpClientToCurl.Sample.InConsole\HttpClientToCurl.Sample.InConsole.csproj", "{323022D2-AAA7-443B-895C-77F5B1634D68}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClientToCurl.Sample.InString", "examples\HttpClientToCurl.Sample.InString\HttpClientToCurl.Sample.InString.csproj", "{F7B35144-A00C-45BE-BC41-36C1B21FCD18}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClientToCurl.Sample.InFile", "examples\HttpClientToCurl.Sample.InFile\HttpClientToCurl.Sample.InFile.csproj", "{403B236B-D7D8-43FB-B47E-DCCAF8BA96C4}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D3967ABF-F7C6-4432-9B67-A3F804CBC3E7}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{E36BF269-7F5D-4DE7-99B0-14567F9CD6B3}"
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solutionItems", "solutionItems", "{3C59B0E2-F8B4-41D0-9E27-5A1B04411241}"
21 | ProjectSection(SolutionItems) = preProject
22 | pre-commit = pre-commit
23 | pre-push = pre-push
24 | EndProjectSection
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClientToCurl.Sample.InGlobal", "examples\HttpClientToCurl.Sample.InGlobal\HttpClientToCurl.Sample.InGlobal.csproj", "{5A8427BC-0821-E973-7221-263D13156248}"
27 | EndProject
28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClientToCurlTest", "tests\HttpClientToCurlTest\HttpClientToCurlTest.csproj", "{8CC76F1F-5845-D81E-5E9A-113F913A444B}"
29 | EndProject
30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpRequestMessageToCurlTest", "tests\HttpRequestMessageToCurlTest\HttpRequestMessageToCurlTest.csproj", "{69E31075-F14E-1DE2-1D6E-D934A5C0480F}"
31 | EndProject
32 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClientToCurl.Sample.InSpecific", "examples\HttpClientToCurl.Sample.InSpecific\HttpClientToCurl.Sample.InSpecific.csproj", "{9D56718F-C9E6-4C45-926D-97599072DA35}"
33 | EndProject
34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpMessageHandlerTest", "tests\HttpMessageHandlerTest\HttpMessageHandlerTest.csproj", "{EF2591EB-8810-433B-BAD6-A41540801342}"
35 | EndProject
36 | Global
37 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
38 | Debug|Any CPU = Debug|Any CPU
39 | Release|Any CPU = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
42 | {18B3309D-B84C-453D-8EF7-16CA9E58F5DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {18B3309D-B84C-453D-8EF7-16CA9E58F5DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {18B3309D-B84C-453D-8EF7-16CA9E58F5DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {18B3309D-B84C-453D-8EF7-16CA9E58F5DC}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {323022D2-AAA7-443B-895C-77F5B1634D68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {323022D2-AAA7-443B-895C-77F5B1634D68}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {323022D2-AAA7-443B-895C-77F5B1634D68}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {323022D2-AAA7-443B-895C-77F5B1634D68}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {F7B35144-A00C-45BE-BC41-36C1B21FCD18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {F7B35144-A00C-45BE-BC41-36C1B21FCD18}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {F7B35144-A00C-45BE-BC41-36C1B21FCD18}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {F7B35144-A00C-45BE-BC41-36C1B21FCD18}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {403B236B-D7D8-43FB-B47E-DCCAF8BA96C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {403B236B-D7D8-43FB-B47E-DCCAF8BA96C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {403B236B-D7D8-43FB-B47E-DCCAF8BA96C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {403B236B-D7D8-43FB-B47E-DCCAF8BA96C4}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {5A8427BC-0821-E973-7221-263D13156248}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {5A8427BC-0821-E973-7221-263D13156248}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {5A8427BC-0821-E973-7221-263D13156248}.Release|Any CPU.ActiveCfg = Release|Any CPU
61 | {5A8427BC-0821-E973-7221-263D13156248}.Release|Any CPU.Build.0 = Release|Any CPU
62 | {8CC76F1F-5845-D81E-5E9A-113F913A444B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {8CC76F1F-5845-D81E-5E9A-113F913A444B}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {8CC76F1F-5845-D81E-5E9A-113F913A444B}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {8CC76F1F-5845-D81E-5E9A-113F913A444B}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {69E31075-F14E-1DE2-1D6E-D934A5C0480F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {69E31075-F14E-1DE2-1D6E-D934A5C0480F}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {69E31075-F14E-1DE2-1D6E-D934A5C0480F}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {69E31075-F14E-1DE2-1D6E-D934A5C0480F}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {9D56718F-C9E6-4C45-926D-97599072DA35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {9D56718F-C9E6-4C45-926D-97599072DA35}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {9D56718F-C9E6-4C45-926D-97599072DA35}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {9D56718F-C9E6-4C45-926D-97599072DA35}.Release|Any CPU.Build.0 = Release|Any CPU
74 | {EF2591EB-8810-433B-BAD6-A41540801342}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {EF2591EB-8810-433B-BAD6-A41540801342}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {EF2591EB-8810-433B-BAD6-A41540801342}.Release|Any CPU.ActiveCfg = Release|Any CPU
77 | {EF2591EB-8810-433B-BAD6-A41540801342}.Release|Any CPU.Build.0 = Release|Any CPU
78 | EndGlobalSection
79 | GlobalSection(SolutionProperties) = preSolution
80 | HideSolutionNode = FALSE
81 | EndGlobalSection
82 | GlobalSection(NestedProjects) = preSolution
83 | {18B3309D-B84C-453D-8EF7-16CA9E58F5DC} = {D3967ABF-F7C6-4432-9B67-A3F804CBC3E7}
84 | {323022D2-AAA7-443B-895C-77F5B1634D68} = {A8574DB9-8411-4F81-A82E-F97AD00EF8AF}
85 | {F7B35144-A00C-45BE-BC41-36C1B21FCD18} = {A8574DB9-8411-4F81-A82E-F97AD00EF8AF}
86 | {403B236B-D7D8-43FB-B47E-DCCAF8BA96C4} = {A8574DB9-8411-4F81-A82E-F97AD00EF8AF}
87 | {5A8427BC-0821-E973-7221-263D13156248} = {A8574DB9-8411-4F81-A82E-F97AD00EF8AF}
88 | {8CC76F1F-5845-D81E-5E9A-113F913A444B} = {E36BF269-7F5D-4DE7-99B0-14567F9CD6B3}
89 | {69E31075-F14E-1DE2-1D6E-D934A5C0480F} = {E36BF269-7F5D-4DE7-99B0-14567F9CD6B3}
90 | {9D56718F-C9E6-4C45-926D-97599072DA35} = {A8574DB9-8411-4F81-A82E-F97AD00EF8AF}
91 | {EF2591EB-8810-433B-BAD6-A41540801342} = {E36BF269-7F5D-4DE7-99B0-14567F9CD6B3}
92 | EndGlobalSection
93 | GlobalSection(ExtensibilityGlobals) = postSolution
94 | SolutionGuid = {E5E0FFF6-54C3-4BA1-91F3-EF3513A18D5D}
95 | EndGlobalSection
96 | EndGlobal
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🥇 HttpClientToCurl
2 |
3 | Generate curl commands directly from your `HttpClient` or `HttpRequestMessage` in .NET — perfect for debugging, logging, and sharing HTTP requests.
4 |
5 | ---
6 |
7 | ## 💖 **Love HttpClientToCurl? Please support us!**
8 |
9 | If this project has made your life easier, consider buying us a coffee or sending a donation.
10 | Every bit of support keeps us motivated, helps us add new features, fix bugs, and maintain the project — keeping it free and awesome for everyone! ☕🚀
11 |
12 | *USDT (Tether – BEP20 / Binance Smart Chain) wallet address:*
13 | `0x9d03Be8B979453bE300724FD4bb3eF77517d45AE`
14 |
15 | ---
16 |
17 | ### 📊 Badges
18 | [](https://github.com/amingolmahalle/HttpClientToCurlGenerator/blob/master/LICENSE)
19 | [](https://github.com/amingolmahalle/HttpClientToCurlGenerator/stargazers)
20 | [](https://www.nuget.org/packages/HttpClientToCurl/)
21 | [](https://www.nuget.org/packages/HttpClientToCurl/)
22 | 
23 |
24 | ---
25 |
26 | ## 📖 Overview
27 | **HttpClientToCurl** is a lightweight and powerful .NET extension library that turns your HTTP requests into curl commands.
28 | It works with both **`HttpClient`** and **`HttpRequestMessage`**, giving you two simple ways to generate curl commands:
29 |
30 | ---
31 |
32 | ### 🧰 1. Manual Mode
33 |
34 | Generate curl commands **on demand** using extension methods on either `HttpClient` or `HttpRequestMessage`.
35 |
36 | **Best for:**
37 | Debugging individual requests, creating reproducible Postman calls, or sharing API examples.
38 |
39 | ---
40 |
41 | ### 🧩 2. Automatic Mode
42 |
43 | Automatically generates curl output whenever your app sends a request.
44 | You can configure it through dependency injection:
45 |
46 | - **Global Registration** — enable for all `HttpClient` instances created via `IHttpClientFactory`
47 | - **Per-Client Registration** — enable only for selected clients
48 |
49 | **Best for:**
50 | Logging, monitoring, or tracing outgoing requests across the application.
51 |
52 | ---
53 |
54 | ### 💡 Why Use HttpClientToCurl?
55 |
56 | - 🧪 Instantly visualise and debug request payloads or headers
57 | - 🤝 Share exact API calls with teammates or QA engineers
58 | - ⚙️ Simplify Postman and CLI reproduction
59 | - 🧩 Lightweight, dependency-free, and easy to integrate
60 |
61 | ---
62 | ## ⚙️ Installation
63 |
64 | ```bash
65 | dotnet add package HttpClientToCurl
66 | ```
67 | Or visit the NuGet page here: HttpClientToCurl
68 |
69 | ## 📚 Documentation
70 |
71 | For full examples, detailed usage, and advanced configuration options, please see the **Wiki**:
72 |
73 | 👉 [Open Wiki → More Details](https://github.com/amingolmahalle/HttpClientToCurlGenerator/wiki)
74 |
75 | ---
76 |
77 | ## 🚀 Quick Start
78 |
79 | ## 🧰 Manual Mode Usage Example
80 |
81 | ```csharp
82 | using System.Text;
83 | using HttpClientToCurl;
84 |
85 | class Program
86 | {
87 | static async Task Main()
88 | {
89 | var baseAddress = new Uri("http://localhost:1213/v1/");
90 | var requestUri = "api/test";
91 |
92 | using var httpClientInstance = new HttpClient { BaseAddress = baseAddress };
93 |
94 | string requestBody = @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
95 | var httpRequestMessageInstance = new HttpRequestMessage(HttpMethod.Post, requestUri)
96 | {
97 | Content = new StringContent(requestBody, Encoding.UTF8, "application/json")
98 | };
99 | httpRequestMessageInstance.Headers.Add("Authorization", "Bearer YourAccessToken");
100 |
101 | // Option 1: Generate curl from HttpClient
102 | httpClientInstance.GenerateCurlInConsole(httpRequestMessageInstance);
103 |
104 | // Option 2: Generate curl from HttpRequestMessage
105 | httpRequestMessageInstance.GenerateCurlInConsole(baseAddress);
106 |
107 | await httpClientInstance.SendAsync(httpRequestMessageInstance);
108 | }
109 | }
110 | ```
111 |
112 | ✅ **Example Output**
113 | ```bash
114 | curl -X POST 'http://localhost:1213/v1/api/test' \
115 | -H 'Authorization: Bearer YourAccessToken' \
116 | -H 'Content-Type: application/json; charset=utf-8' \
117 | -d '{"name":"sara","requestId":10001001,"amount":20000}'
118 | ```
119 |
120 | ---
121 |
122 | ## 🧩 Automatic Mode Usage Example
123 |
124 | ### 1️⃣ Per-Client Registration
125 |
126 | Enable curl logging for specific named clients only.
127 |
128 | **Program.cs / Startup.cs**
129 | ```csharp
130 | using HttpClientToCurl;
131 |
132 | // Register the curl generator once
133 | builder.Services.AddHttpClientToCurl(builder.Configuration);
134 |
135 | // Enable curl logging for selected clients
136 | builder.Services.AddHttpClient("my-client1", showCurl: true);
137 | ```
138 |
139 | **appsettings.json**
140 | ```json
141 | "HttpClientToCurl": {
142 | "Enable": true, // Master switch: enable or disable the entire HttpClientToCURL logging system
143 |
144 | "ShowOnConsole": {
145 | "TurnOn": true, // Enable console output for generated curl commands
146 | "NeedAddDefaultHeaders": true, // Include default headers (like User-Agent, Accept, etc.) in the curl output
147 | "EnableCompression": false, // Compress the console log output (not recommended for debugging readability)
148 | "EnableCodeBeautification": true // Beautify and format the curl command for better readability
149 | },
150 |
151 | "SaveToFile": {
152 | "TurnOn": true, // Enable saving the generated curl commands into a file
153 | "NeedAddDefaultHeaders": true, // Include default headers (like User-Agent, Accept, etc.) in the curl output
154 | "EnableCompression": false, // Compress the saved file (useful if logging a large number of requests)
155 | "Filename": "curl_commands", // Name of the output file without extension (e.g., will produce curl_commands.log)
156 | "Path": "C:\\Users\\Public" // Directory path where the log file will be created
157 | },
158 |
159 | "SendToLogger": {
160 | "TurnOn": true, // Enable sending curl commands to ILogger (integrates with Application Insights, Seq, Serilog, etc.)
161 | "NeedAddDefaultHeaders": true, // Include default headers (like User-Agent, Accept, etc.) in the curl output
162 | "EnableCompression": false, // Compress the logged output
163 | "LogLevel": "Debug" // Log level: Trace, Debug, Information, Warning, Error, Critical
164 | }
165 | }
166 | ```
167 |
168 | ---
169 |
170 | ### 2️⃣ Global Registration
171 |
172 | Enable curl generation globally — every `HttpClient` created through `IHttpClientFactory` will automatically log curl commands.
173 |
174 | **Program.cs / Startup.cs**
175 | ```csharp
176 | using HttpClientToCurl;
177 |
178 | // Register global curl generation
179 | builder.Services.AddAllHttpClientToCurl(builder.Configuration);
180 |
181 | // Register default HttpClient (now curl-enabled)
182 | builder.Services.AddHttpClient();
183 | ```
184 |
185 | **appsettings.json**
186 | (same configuration options as above)
187 |
188 | ---
189 |
190 | ## 🧩 Features
191 |
192 | | Feature | Description |
193 | |----------|--------------|
194 | | 🔁 Methods | Supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |
195 | | 🧠 Content Types | `JSON`, `XML`, `FormUrlEncodedContent` |
196 | | 💾 Output | Console • File • String • ILogger |
197 | | 🎨 Beautified Output | Optional pretty printing |
198 | | 📊 Logging Integration | Works with Application Insights, Seq, Serilog, and other ILogger providers |
199 |
200 | ---
201 |
202 | ## 📚 Articles
203 |
204 | - [How to Generate curl Script of the HttpClient in .NET](https://www.c-sharpcorner.com/article/how-to-generate-curl-script-of-the-httpclient-in-net/)
205 | - [New Feature in HttpClientToCurl for .NET: Debugging HttpRequestMessage Made Easy](https://medium.com/@mozhgan.etaati/new-feature-in-httpclienttocurl-for-net-debugging-httprequestmessage-made-easy-18cb66dd55f0)
206 |
207 |
208 | ## 💡 **Contribute**
209 |
210 | Found a bug or want to improve this project?
211 | Open an issue or submit a pull request.
212 |
213 | 📧 Contact: amin.golmahalle@gmail.com
214 |
215 | ## ⭐ **Give a Star**
216 |
217 | If you find this project helpful, please give it a ⭐ — it helps others discover it too!
218 |
219 | ## 🙌 **Contributors**
220 |
221 |
222 |
--------------------------------------------------------------------------------
/src/HttpClientToCurl/Builder/Concrete/Common/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using System.Web;
3 | using HttpClientToCurl.Utility;
4 |
5 | namespace HttpClientToCurl.Builder.Concrete.Common;
6 |
7 | internal static class Extensions
8 | {
9 | internal static StringBuilder Initialize(this StringBuilder stringBuilder, HttpMethod httpMethod)
10 | {
11 | stringBuilder.Append("curl");
12 |
13 | if (httpMethod != HttpMethod.Get)
14 | {
15 | stringBuilder
16 | .Append(' ')
17 | .Append("-X")
18 | .Append(' ')
19 | .Append(httpMethod.Method);
20 | }
21 |
22 | return stringBuilder.Append(' ');
23 | }
24 |
25 | internal static string Finalize(this StringBuilder stringBuilder, bool enableCompression)
26 | {
27 | return enableCompression
28 | ? stringBuilder
29 | .Append(' ')
30 | .Append("--compressed")
31 | .ToString()
32 | : stringBuilder.ToString();
33 | }
34 |
35 | internal static StringBuilder AddAbsoluteUrl(this StringBuilder stringBuilder, string baseAddress, Uri requestUri)
36 | {
37 | Uri baseAddressUri = Helpers.CreateUri(baseAddress);
38 | bool baseAddressIsAbsoluteUri = Helpers.CheckAddressIsAbsoluteUri(baseAddressUri);
39 | bool requestUriIsAbsoluteUri = Helpers.CheckAddressIsAbsoluteUri(requestUri);
40 |
41 | string address = GetAbsoluteAddress(baseAddressUri, baseAddressIsAbsoluteUri, requestUri, requestUriIsAbsoluteUri);
42 |
43 | var encodedAddress = address.ApplyEncodeUri();
44 |
45 | return stringBuilder
46 | .Append($"{AddSingleQuotationMark(encodedAddress ?? address)}")
47 | .Append(' ');
48 |
49 | static string AddSingleQuotationMark(string address)
50 | {
51 | return address is not null ? $"'{address}'" : null;
52 | }
53 | }
54 |
55 | private static string GetAbsoluteAddress(Uri baseAddressUri, bool baseAddressIsAbsoluteUri, Uri requestUri, bool requestUriIsAbsoluteUri)
56 | {
57 | if (requestUri is null && baseAddressUri is not null && baseAddressIsAbsoluteUri)
58 | {
59 | return baseAddressUri.ToString();
60 | }
61 |
62 | if (baseAddressUri is null && requestUri is not null && requestUriIsAbsoluteUri)
63 | {
64 | return requestUri.ToString();
65 | }
66 |
67 | if (baseAddressUri is not null && requestUri is not null && baseAddressIsAbsoluteUri && !requestUriIsAbsoluteUri)
68 | {
69 | return new Uri(baseAddressUri, requestUri).ToString();
70 | }
71 |
72 | if (baseAddressUri is not null && requestUri is not null && baseAddressIsAbsoluteUri)
73 | {
74 | return requestUri.ToString();
75 | }
76 |
77 | if (baseAddressUri is null && requestUri is null)
78 | {
79 | return null;
80 | }
81 |
82 | return $"{baseAddressUri}{requestUri}";
83 | }
84 |
85 | private static string ApplyEncodeUri(this string address)
86 | {
87 | if (address is not null)
88 | {
89 | var questionMarkItems = address.Split('?');
90 | if (questionMarkItems.Length > 1)
91 | {
92 | var andItems = questionMarkItems[1].Split('&');
93 | if (andItems.Length > 1)
94 | {
95 | var addressEncodedStringBuilder = new StringBuilder()
96 | .Append(questionMarkItems[0])
97 | .Append('?');
98 | foreach (var ai in andItems)
99 | {
100 | var equalItems = ai.Split('=');
101 | if (equalItems.Length > 1)
102 | {
103 | addressEncodedStringBuilder
104 | .Append(equalItems[0])
105 | .Append('=')
106 | .Append(Uri.EscapeDataString(equalItems[1]))
107 | .Append('&');
108 | }
109 | }
110 |
111 | return addressEncodedStringBuilder
112 | .Remove(addressEncodedStringBuilder.Length - 1, 1)
113 | .ToString();
114 | }
115 | }
116 | }
117 |
118 | return null;
119 | }
120 |
121 | internal static StringBuilder AddHeaders(this StringBuilder stringBuilder, HttpClient httpClient,
122 | HttpRequestMessage httpRequestMessage, bool needAddDefaultHeaders = true)
123 | {
124 | bool hasHeader = false;
125 |
126 | if (needAddDefaultHeaders && httpClient.DefaultRequestHeaders.Any())
127 | {
128 | var defaultHeaders =
129 | httpClient.DefaultRequestHeaders.Where(dh => dh.Key != Constants.ContentLength);
130 | foreach (var header in defaultHeaders)
131 | {
132 | stringBuilder
133 | .Append("-H")
134 | .Append(' ')
135 | .Append($"\'{header.Key}: {string.Join("; ", header.Value)}\'")
136 | .Append(' ');
137 | }
138 |
139 | hasHeader = true;
140 | }
141 |
142 | if (httpRequestMessage.Headers.Any())
143 | {
144 | var headers = httpRequestMessage.Headers.Where(h => h.Key != Constants.ContentLength);
145 | foreach (var header in headers)
146 | {
147 | stringBuilder
148 | .Append("-H")
149 | .Append(' ')
150 | .Append($"\'{header.Key}: {string.Join("; ", header.Value)}\'")
151 | .Append(' ');
152 | }
153 |
154 | hasHeader = true;
155 | }
156 |
157 | if (httpRequestMessage.Content is not null && httpRequestMessage.Content.Headers.Any())
158 | {
159 | foreach (var header in httpRequestMessage.Content.Headers.Where(h => h.Key != Constants.ContentLength))
160 | {
161 | stringBuilder
162 | .Append("-H")
163 | .Append(' ')
164 | .Append($"\'{header.Key}: {string.Join("; ", header.Value)}\'")
165 | .Append(' ');
166 | }
167 |
168 | hasHeader = true;
169 | }
170 |
171 | if (!hasHeader)
172 | {
173 | stringBuilder.Append(' ');
174 | }
175 |
176 | return stringBuilder;
177 | }
178 |
179 | internal static StringBuilder AddHeaders(this StringBuilder stringBuilder,
180 | HttpRequestMessage httpRequestMessage)
181 | {
182 | bool hasHeader = false;
183 |
184 | if (httpRequestMessage.Headers.Any())
185 | {
186 | var headers = httpRequestMessage.Headers.Where(h => h.Key != Constants.ContentLength);
187 | foreach (var header in headers)
188 | {
189 | stringBuilder
190 | .Append("-H")
191 | .Append(' ')
192 | .Append($"\'{header.Key}: {string.Join("; ", header.Value)}\'")
193 | .Append(' ');
194 | }
195 |
196 | hasHeader = true;
197 | }
198 |
199 | if (httpRequestMessage.Content is not null && httpRequestMessage.Content.Headers.Any())
200 | {
201 | foreach (var header in httpRequestMessage.Content.Headers.Where(h => h.Key != Constants.ContentLength))
202 | {
203 | stringBuilder
204 | .Append("-H")
205 | .Append(' ')
206 | .Append($"\'{header.Key}: {string.Join("; ", header.Value)}\'")
207 | .Append(' ');
208 | }
209 |
210 | hasHeader = true;
211 | }
212 |
213 | if (!hasHeader)
214 | {
215 | stringBuilder.Append(' ');
216 | }
217 |
218 | return stringBuilder;
219 | }
220 |
221 | internal static StringBuilder AddBody(this StringBuilder stringBuilder, HttpContent content)
222 | {
223 | string contentType = content?.Headers?.ContentType?.MediaType;
224 | string body = content?.ReadAsStringAsync().GetAwaiter().GetResult();
225 |
226 | if (contentType == Constants.FormUrlEncodedContentType)
227 | {
228 | stringBuilder.AddFormUrlEncodedContentBody(body);
229 | }
230 | else
231 | {
232 | stringBuilder.AppendBodyItem(body);
233 | }
234 |
235 | return stringBuilder;
236 | }
237 |
238 | private static void AppendBodyItem(this StringBuilder stringBuilder, object body)
239 | => stringBuilder
240 | .Append("-d")
241 | .Append(' ')
242 | .Append('\'')
243 | .Append(body)
244 | .Append('\'')
245 | .Append(' ');
246 |
247 | private static void AddFormUrlEncodedContentBody(this StringBuilder stringBuilder, string body)
248 | {
249 | string decodedBody = HttpUtility.UrlDecode(body);
250 | string[] splitBodyArray = decodedBody.Split('&');
251 | if (splitBodyArray.Any())
252 | {
253 | foreach (string item in splitBodyArray)
254 | {
255 | stringBuilder.AppendBodyItem(item);
256 | }
257 | }
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # Tye
66 | .tye/
67 |
68 | # ASP.NET Scaffolding
69 | ScaffoldingReadMe.txt
70 |
71 | # StyleCop
72 | StyleCopReport.xml
73 |
74 | # Files built by Visual Studio
75 | *_i.c
76 | *_p.c
77 | *_h.h
78 | *.ilk
79 | *.meta
80 | *.obj
81 | *.iobj
82 | *.pch
83 | *.pdb
84 | *.ipdb
85 | *.pgc
86 | *.pgd
87 | *.rsp
88 | *.sbr
89 | *.tlb
90 | *.tli
91 | *.tlh
92 | *.tmp
93 | *.tmp_proj
94 | *_wpftmp.csproj
95 | *.log
96 | *.vspscc
97 | *.vssscc
98 | .builds
99 | *.pidb
100 | *.svclog
101 | *.scc
102 |
103 | # Chutzpah Test files
104 | _Chutzpah*
105 |
106 | # Visual C++ cache files
107 | ipch/
108 | *.aps
109 | *.ncb
110 | *.opendb
111 | *.opensdf
112 | *.sdf
113 | *.cachefile
114 | *.VC.db
115 | *.VC.VC.opendb
116 |
117 | # Visual Studio profiler
118 | *.psess
119 | *.vsp
120 | *.vspx
121 | *.sap
122 |
123 | # Visual Studio Trace Files
124 | *.e2e
125 |
126 | # TFS 2012 Local Workspace
127 | $tf/
128 |
129 | # Guidance Automation Toolkit
130 | *.gpState
131 |
132 | # ReSharper is a .NET coding add-in
133 | _ReSharper*/
134 | *.[Rr]e[Ss]harper
135 | *.DotSettings.user
136 |
137 | # TeamCity is a build add-in
138 | _TeamCity*
139 |
140 | # DotCover is a Code Coverage Tool
141 | *.dotCover
142 |
143 | # AxoCover is a Code Coverage Tool
144 | .axoCover/*
145 | !.axoCover/settings.json
146 |
147 | # Coverlet is a free, cross platform Code Coverage Tool
148 | coverage*.json
149 | coverage*.xml
150 | coverage*.info
151 |
152 | # Visual Studio code coverage results
153 | *.coverage
154 | *.coveragexml
155 |
156 | # NCrunch
157 | _NCrunch_*
158 | .*crunch*.local.xml
159 | nCrunchTemp_*
160 |
161 | # MightyMoose
162 | *.mm.*
163 | AutoTest.Net/
164 |
165 | # Web workbench (sass)
166 | .sass-cache/
167 |
168 | # Installshield output folder
169 | [Ee]xpress/
170 |
171 | # DocProject is a documentation generator add-in
172 | DocProject/buildhelp/
173 | DocProject/Help/*.HxT
174 | DocProject/Help/*.HxC
175 | DocProject/Help/*.hhc
176 | DocProject/Help/*.hhk
177 | DocProject/Help/*.hhp
178 | DocProject/Help/Html2
179 | DocProject/Help/html
180 |
181 | # Click-Once directory
182 | publish/
183 |
184 | # Publish Web Output
185 | *.[Pp]ublish.xml
186 | *.azurePubxml
187 | # Note: Comment the next line if you want to checkin your web deploy settings,
188 | # but database connection strings (with potential passwords) will be unencrypted
189 | *.pubxml
190 | *.publishproj
191 |
192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
193 | # checkin your Azure Web App publish settings, but sensitive information contained
194 | # in these scripts will be unencrypted
195 | PublishScripts/
196 |
197 | # NuGet Packages
198 | *.nupkg
199 | # NuGet Symbol Packages
200 | *.snupkg
201 | # The packages folder can be ignored because of Package Restore
202 | **/[Pp]ackages/*
203 | # except build/, which is used as an MSBuild target.
204 | !**/[Pp]ackages/build/
205 | # Uncomment if necessary however generally it will be regenerated when needed
206 | #!**/[Pp]ackages/repositories.config
207 | # NuGet v3's project.json files produces more ignorable files
208 | *.nuget.props
209 | *.nuget.targets
210 |
211 | # Microsoft Azure Build Output
212 | csx/
213 | *.build.csdef
214 |
215 | # Microsoft Azure Emulator
216 | ecf/
217 | rcf/
218 |
219 | # Windows Store app package directories and files
220 | AppPackages/
221 | BundleArtifacts/
222 | Package.StoreAssociation.xml
223 | _pkginfo.txt
224 | *.appx
225 | *.appxbundle
226 | *.appxupload
227 |
228 | # Visual Studio cache files
229 | # files ending in .cache can be ignored
230 | *.[Cc]ache
231 | # but keep track of directories ending in .cache
232 | !?*.[Cc]ache/
233 |
234 | # Others
235 | ClientBin/
236 | ~$*
237 | *~
238 | *.dbmdl
239 | *.dbproj.schemaview
240 | *.jfm
241 | *.pfx
242 | *.publishsettings
243 | orleans.codegen.cs
244 |
245 | # Including strong name files can present a security risk
246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
247 | #*.snk
248 |
249 | # Since there are multiple workflows, uncomment next line to ignore bower_components
250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
251 | #bower_components/
252 |
253 | # RIA/Silverlight projects
254 | Generated_Code/
255 |
256 | # Backup & report files from converting an old project file
257 | # to a newer Visual Studio version. Backup files are not needed,
258 | # because we have git ;-)
259 | _UpgradeReport_Files/
260 | Backup*/
261 | UpgradeLog*.XML
262 | UpgradeLog*.htm
263 | ServiceFabricBackup/
264 | *.rptproj.bak
265 |
266 | # SQL Server files
267 | *.mdf
268 | *.ldf
269 | *.ndf
270 |
271 | # Business Intelligence projects
272 | *.rdl.data
273 | *.bim.layout
274 | *.bim_*.settings
275 | *.rptproj.rsuser
276 | *- [Bb]ackup.rdl
277 | *- [Bb]ackup ([0-9]).rdl
278 | *- [Bb]ackup ([0-9][0-9]).rdl
279 |
280 | # Microsoft Fakes
281 | FakesAssemblies/
282 |
283 | # GhostDoc plugin setting file
284 | *.GhostDoc.xml
285 |
286 | # Node.js Tools for Visual Studio
287 | .ntvs_analysis.dat
288 | node_modules/
289 |
290 | # Visual Studio 6 build log
291 | *.plg
292 |
293 | # Visual Studio 6 workspace options file
294 | *.opt
295 |
296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
297 | *.vbw
298 |
299 | # Visual Studio LightSwitch build output
300 | **/*.HTMLClient/GeneratedArtifacts
301 | **/*.DesktopClient/GeneratedArtifacts
302 | **/*.DesktopClient/ModelManifest.xml
303 | **/*.Server/GeneratedArtifacts
304 | **/*.Server/ModelManifest.xml
305 | _Pvt_Extensions
306 |
307 | # Paket dependency manager
308 | .paket/paket.exe
309 | paket-files/
310 |
311 | # FAKE - F# Make
312 | .fake/
313 |
314 | # CodeRush personal settings
315 | .cr/personal
316 |
317 | # Python Tools for Visual Studio (PTVS)
318 | __pycache__/
319 | *.pyc
320 |
321 | # Cake - Uncomment if you are using it
322 | # tools/**
323 | # !tools/packages.config
324 |
325 | # Tabs Studio
326 | *.tss
327 |
328 | # Telerik's JustMock configuration file
329 | *.jmconfig
330 |
331 | # BizTalk build output
332 | *.btp.cs
333 | *.btm.cs
334 | *.odx.cs
335 | *.xsd.cs
336 |
337 | # OpenCover UI analysis results
338 | OpenCover/
339 |
340 | # Azure Stream Analytics local run output
341 | ASALocalRun/
342 |
343 | # MSBuild Binary and Structured Log
344 | *.binlog
345 |
346 | # NVidia Nsight GPU debugger configuration file
347 | *.nvuser
348 |
349 | # MFractors (Xamarin productivity tool) working folder
350 | .mfractor/
351 |
352 | # Local History for Visual Studio
353 | .localhistory/
354 |
355 | # BeatPulse healthcheck temp database
356 | healthchecksdb
357 |
358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
359 | MigrationBackup/
360 |
361 | # Ionide (cross platform F# VS Code tools) working folder
362 | .ionide/
363 |
364 | # Fody - auto-generated XML schema
365 | FodyWeavers.xsd
366 |
367 | ##
368 | ## Visual studio for Mac
369 | ##
370 |
371 |
372 | # globs
373 | Makefile.in
374 | *.userprefs
375 | *.usertasks
376 | config.make
377 | config.status
378 | aclocal.m4
379 | install-sh
380 | autom4te.cache/
381 | *.tar.gz
382 | tarballs/
383 | test-results/
384 |
385 | # Mac bundle stuff
386 | *.dmg
387 | *.app
388 |
389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
390 | # General
391 | .DS_Store
392 | .AppleDouble
393 | .LSOverride
394 |
395 | # Icon must end with two \r
396 | Icon
397 |
398 |
399 | # Thumbnails
400 | ._*
401 |
402 | # Files that might appear in the root of a volume
403 | .DocumentRevisions-V100
404 | .fseventsd
405 | .Spotlight-V100
406 | .TemporaryItems
407 | .Trashes
408 | .VolumeIcon.icns
409 | .com.apple.timemachine.donotpresent
410 |
411 | # Directories potentially created on remote AFP share
412 | .AppleDB
413 | .AppleDesktop
414 | Network Trash Folder
415 | Temporary Items
416 | .apdisk
417 |
418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
419 | # Windows thumbnail cache files
420 | Thumbs.db
421 | ehthumbs.db
422 | ehthumbs_vista.db
423 |
424 | # Dump file
425 | *.stackdump
426 |
427 | # Folder config file
428 | [Dd]esktop.ini
429 |
430 | # Recycle Bin used on file shares
431 | $RECYCLE.BIN/
432 |
433 | # Windows Installer files
434 | *.cab
435 | *.msi
436 | *.msix
437 | *.msm
438 | *.msp
439 |
440 | # Windows shortcuts
441 | *.lnk
442 |
443 | # JetBrains Rider
444 | .idea/
445 | *.sln.iml
446 |
447 | ##
448 | ## Visual Studio Code
449 | ##
450 | .vscode/*
451 | !.vscode/settings.json
452 | !.vscode/tasks.json
453 | !.vscode/launch.json
454 | !.vscode/extensions.json
455 |
--------------------------------------------------------------------------------
/tests/HttpRequestMessageToCurlTest/FunctionalTest/SuccessScenariosTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using FluentAssertions;
4 | using HttpClientToCurl.Extensions;
5 | using HttpClientToCurl.Utility;
6 | using Microsoft.AspNetCore.WebUtilities;
7 | using Xunit;
8 |
9 | namespace HttpRequestMessageToCurlTest.FunctionalTest;
10 |
11 | public class SuccessScenariosTests
12 | {
13 | #region :: GenerateCurlInString For Post Method ::
14 |
15 | [Fact]
16 | public void Success_GenerateCurlInString_For_PostMethod()
17 | {
18 | // Arrange
19 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
20 |
21 | var requestUri = "api/test";
22 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
23 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
24 | var baseAddress = new Uri("http://localhost:1213/v1/");
25 | // Act
26 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
27 |
28 | // Assert
29 | curlResult.Should().NotBeNullOrEmpty();
30 | curlResult.Should().StartWith("curl -X POST");
31 | curlResult.Trim().Should()
32 | .BeEquivalentTo(
33 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
34 | }
35 |
36 | [Fact]
37 | public void Success_GenerateCurlInString_With_RequestUri_TypeOf_Uri_For_PostMethod()
38 | {
39 | // Arrange
40 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
41 |
42 | var requestUri = Helpers.CreateUri("api/test");
43 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
44 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
45 |
46 | var baseAddress = new Uri("http://localhost:1213/v1/");
47 |
48 | // Act
49 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
50 |
51 | // Assert
52 | curlResult.Should().NotBeNullOrEmpty();
53 | curlResult.Should().StartWith("curl -X POST");
54 | curlResult.Trim().Should()
55 | .BeEquivalentTo(
56 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
57 | }
58 |
59 | [Fact]
60 | public void GenerateCurl_When_Set_RequestUri_Inside_HttpRequestMessage_For_PostMethod()
61 | {
62 | // Arrange
63 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
64 |
65 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "api/test") { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
66 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
67 |
68 | using var httpClient = new HttpClient();
69 | var baseAddress = new Uri("http://localhost:1213/v1/");
70 |
71 | // Act
72 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
73 |
74 | // Assert
75 | curlResult.Should().NotBeNullOrEmpty();
76 | curlResult.Should().StartWith("curl -X POST");
77 | curlResult.Trim().Should()
78 | .BeEquivalentTo(
79 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
80 | }
81 |
82 | [Fact]
83 | public void Success_GenerateCurlInString_When_RequestUri_Is_Null_For_PostMethod()
84 | {
85 | // Arrange
86 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
87 |
88 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, string.Empty) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
89 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
90 |
91 | var baseAddress = new Uri("http://localhost:1213/v1/");
92 |
93 | // Act
94 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
95 |
96 | // Assert
97 | curlResult.Should().NotBeNullOrEmpty();
98 | curlResult.Should().StartWith("curl -X POST");
99 | curlResult.Trim().Should()
100 | .BeEquivalentTo(
101 | @"curl -X POST 'http://localhost:1213/v1/' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
102 | }
103 |
104 | [Fact]
105 | public void Success_GenerateCurlInString_When_RequestBody_Is_Null_For_PostMethod()
106 | {
107 | // Arrange
108 | var requestUri = "api/test";
109 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
110 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
111 |
112 | var baseAddress = new Uri("http://localhost:1213/v1/");
113 |
114 | // Act
115 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
116 |
117 | // Assert
118 | curlResult.Should().NotBeNullOrEmpty();
119 | curlResult.Should().StartWith("curl -X POST");
120 | curlResult.Trim().Should()
121 | .BeEquivalentTo(
122 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d ''");
123 | }
124 |
125 | [Fact]
126 | public void Success_GenerateCurlInString_When_HttpContent_Is_Null_For_PostMethod()
127 | {
128 | // Arrange
129 | var requestUri = "api/test";
130 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
131 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
132 |
133 | using var httpClient = new HttpClient();
134 | var baseAddress = new Uri("http://localhost:1213/v1/");
135 |
136 | // Act
137 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
138 |
139 | // Assert
140 | curlResult.Should().NotBeNullOrEmpty();
141 | curlResult.Should().StartWith("curl -X POST");
142 | curlResult.Trim().Should().BeEquivalentTo(@"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -d ''");
143 | }
144 |
145 | [Fact]
146 | public void Success_GenerateCurlInString_With_Multiple_Value_For_A_Header_PostMethod()
147 | {
148 | // Arrange
149 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
150 |
151 | var requestUri = "api/test";
152 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
153 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
154 |
155 | List headerValues = ["_ga=GA1.1.41226618.1701506283", "mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05", "sp_ses.13cb=*"];
156 | httpRequestMessage.Headers.Add("cookie", headerValues);
157 |
158 | var baseAddress = new Uri("http://localhost:1213/v1/");
159 |
160 | // Act
161 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
162 |
163 | // Assert
164 | curlResult.Should().NotBeNullOrEmpty();
165 | curlResult.Should().StartWith("curl -X POST");
166 | curlResult.Trim().Should()
167 | .BeEquivalentTo(
168 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Cookie: _ga=GA1.1.41226618.1701506283; mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05; sp_ses.13cb=*' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
169 | }
170 |
171 | #endregion
172 |
173 | #region :: GenerateCurlInString For Get Method ::
174 |
175 | [Fact]
176 | public void Success_GenerateCurlInString_For_GetMethod()
177 | {
178 | // Arrange
179 | var requestUri = "api/test";
180 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
181 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
182 |
183 | var baseAddress = new Uri("http://localhost:1213/v1/");
184 |
185 | // Act
186 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
187 |
188 | // Assert
189 | curlResult.Should().NotBeNullOrEmpty();
190 | curlResult.Should().StartWith("curl");
191 | curlResult.Trim().Should()
192 | .BeEquivalentTo(
193 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
194 | }
195 |
196 | [Fact]
197 | public void Success_GenerateCurlInString_With_QueryString_For_GetMethod()
198 | {
199 | // Arrange
200 | var queryString = new Dictionary { { "id", "12" } };
201 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
202 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
203 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
204 |
205 | var baseAddress = new Uri("http://localhost:1213/v1/");
206 |
207 | // Act
208 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
209 |
210 | // Assert
211 | curlResult.Should().NotBeNullOrEmpty();
212 | curlResult.Should().StartWith("curl");
213 | curlResult.Trim().Should()
214 | .BeEquivalentTo(
215 | @"curl 'http://localhost:1213/v1/api/test?id=12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
216 | }
217 |
218 | [Fact]
219 | public void Success_GenerateCurlInString_When_RequestUri_Is_Null_For_GetMethod()
220 | {
221 | // Arrange
222 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, string.Empty) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
223 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
224 |
225 | var baseAddress = new Uri("http://localhost:1213/v1/");
226 |
227 | // Act
228 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
229 |
230 | // Assert
231 | curlResult.Should().NotBeNullOrEmpty();
232 | curlResult.Should().StartWith("curl");
233 | curlResult.Trim().Should()
234 | .BeEquivalentTo(@"curl 'http://localhost:1213/v1/' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
235 | }
236 |
237 | [Fact]
238 | public void Success_GenerateCurlInString_With_Multiple_Value_For_A_Header_GetMethod()
239 | {
240 | // Arrange
241 | var requestUri = "api/test";
242 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
243 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
244 |
245 | List headerValues = ["_ga=GA1.1.41226618.1701506283", "mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05", "sp_ses.13cb=*"];
246 | httpRequestMessage.Headers.Add("cookie", headerValues);
247 |
248 | var baseAddress = new Uri("http://localhost:1213/v1/");
249 |
250 | // Act
251 | string curlResult = httpRequestMessage.GenerateCurlInString(baseAddress);
252 |
253 | // Assert
254 | curlResult.Should().NotBeNullOrEmpty();
255 | curlResult.Should().StartWith("curl");
256 | curlResult.Trim().Should()
257 | .BeEquivalentTo(
258 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Cookie: _ga=GA1.1.41226618.1701506283; mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05; sp_ses.13cb=*' -H 'Content-Type: application/json; charset=utf-8'");
259 | }
260 |
261 | #endregion
262 | }
263 |
--------------------------------------------------------------------------------
/tests/HttpMessageHandlerTest/UnitTest/CurlGeneratorHttpMessageHandlerTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using HttpClientToCurl.Config;
3 | using HttpClientToCurl.HttpMessageHandlers;
4 | using HttpMessageHandlerTest.UnitTest.Fakes;
5 | using HttpMessageHandlerTest.UnitTest.Builders;
6 | using FluentAssertions;
7 |
8 | namespace HttpMessageHandlerTest.UnitTest;
9 |
10 | public class CurlGeneratorHttpMessageHandlerTests
11 | {
12 | [Fact]
13 | public async Task CurlGeneratorHttpMessageHandler_ReturnsResponse_When_TurnOffAll()
14 | {
15 | // Arrange
16 | var config = new CompositConfigBuilder()
17 | .SetEnable(false)
18 | .Build();
19 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config))
20 | {
21 | InnerHandler = new FakeHttpMessageHandler()
22 | };
23 |
24 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/test");
25 |
26 | // Act
27 | using var invoker = new HttpMessageInvoker(handler);
28 | var response = await invoker.SendAsync(request, CancellationToken.None);
29 |
30 | // Assert
31 | response.Should().NotBeNull();
32 | response.StatusCode.Should().Be(HttpStatusCode.OK);
33 | }
34 |
35 | [Fact]
36 | public async Task CurlGeneratorHttpMessageHandler_ReturnsResponse_When_Enable_But_ShowOnConsole_And_SaveToFile_AreNot_Configured()
37 | {
38 | // Arrange
39 | var config = new CompositConfigBuilder()
40 | .SetEnable(true)
41 | .SetShowOnConsole(null)
42 | .SetSaveToFile(null)
43 | .Build();
44 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config))
45 | {
46 | InnerHandler = new FakeHttpMessageHandler()
47 | };
48 |
49 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/test");
50 |
51 | // Act
52 | using var invoker = new HttpMessageInvoker(handler);
53 | var response = await invoker.SendAsync(request, CancellationToken.None);
54 |
55 | // Assert
56 | response.Should().NotBeNull();
57 | response.StatusCode.Should().Be(HttpStatusCode.OK);
58 | }
59 |
60 | [Fact]
61 | public async Task CurlGeneratorHttpMessageHandler_ReturnsResponse_When_Enable_But_ShowOnConsole_And_SaveToFile_TurnOff()
62 | {
63 | // Arrange
64 | var config = new CompositConfigBuilder()
65 | .SetEnable(true)
66 | .SetShowOnConsole(new ConsoleConfig
67 | {
68 | TurnOn = false,
69 | })
70 | .SetSaveToFile(new FileConfig()
71 | {
72 | TurnOn = false
73 | })
74 | .Build();
75 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config))
76 | {
77 | InnerHandler = new FakeHttpMessageHandler()
78 | };
79 |
80 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/test");
81 |
82 | // Act
83 | using var invoker = new HttpMessageInvoker(handler);
84 | var response = await invoker.SendAsync(request, CancellationToken.None);
85 |
86 | // Assert
87 | response.Should().NotBeNull();
88 | response.StatusCode.Should().Be(HttpStatusCode.OK);
89 | }
90 |
91 | [Fact]
92 | public async Task CurlGeneratorHttpMessageHandler_WritesToConsole_When_ShowOnConsole_TurnOn()
93 | {
94 | // Arrange
95 | var config = new CompositConfigBuilder()
96 | .SetEnable(true)
97 | .SetShowOnConsole(new ConsoleConfig
98 | {
99 | TurnOn = true,
100 | EnableCodeBeautification = false
101 | })
102 | .Build();
103 |
104 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config))
105 | {
106 | InnerHandler = new FakeHttpMessageHandler()
107 | };
108 |
109 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
110 |
111 | var sw = new StringWriter();
112 | var originalOut = Console.Out;
113 | try
114 | {
115 | Console.SetOut(sw);
116 |
117 | // Act
118 | using var invoker = new HttpMessageInvoker(handler);
119 | var response = await invoker.SendAsync(request, CancellationToken.None);
120 |
121 | // Assert
122 | response.Should().NotBeNull();
123 | response.StatusCode.Should().Be(HttpStatusCode.OK);
124 |
125 | var output = sw.ToString();
126 | output.Should().Contain("curl");
127 | }
128 | finally
129 | {
130 | Console.SetOut(originalOut);
131 | }
132 | }
133 |
134 | [Fact]
135 | public async Task CurlGeneratorHttpMessageHandler_WritesToFile_When_SaveToFile_TurnOn()
136 | {
137 | // Arrange
138 | var tempPath = Path.GetTempPath();
139 | var filename = Guid.NewGuid().ToString("N");
140 |
141 | var config = new CompositConfigBuilder()
142 | .SetEnable(true)
143 | .SetSaveToFile(new FileConfig
144 | {
145 | TurnOn = true,
146 | Path = tempPath,
147 | Filename = filename
148 | })
149 | .Build();
150 |
151 | var monitor = new FakeOptionsMonitor(config);
152 | var handler = new CurlGeneratorHttpMessageHandler(monitor)
153 | {
154 | InnerHandler = new FakeHttpMessageHandler()
155 | };
156 |
157 | var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/test") { Content = new StringContent("hello") };
158 |
159 | var filePath = Path.Combine(tempPath.TrimEnd(Path.DirectorySeparatorChar), filename + ".curl");
160 |
161 | try
162 | {
163 | if (File.Exists(filePath))
164 | {
165 | File.Delete(filePath);
166 | }
167 |
168 | // Act
169 | using var invoker = new HttpMessageInvoker(handler);
170 | var response = await invoker.SendAsync(request, CancellationToken.None);
171 |
172 | // Assert
173 | response.Should().NotBeNull();
174 | response.StatusCode.Should().Be(HttpStatusCode.OK);
175 |
176 | File.Exists(filePath).Should().BeTrue();
177 | var content = File.ReadAllText(filePath);
178 | content.Should().Contain("curl");
179 | }
180 | finally
181 | {
182 | if (File.Exists(filePath))
183 | {
184 | File.Delete(filePath);
185 | }
186 | }
187 | }
188 |
189 | [Fact]
190 | public async Task CurlGeneratorHttpMessageHandler_WritesToConsole_And_WritesToFile_When_ShowOnConsole_And_SaveToFile_TurnOn()
191 | {
192 | // Arrange
193 | var tempPath = Path.GetTempPath();
194 | var filename = Guid.NewGuid().ToString("N");
195 |
196 | var config = new CompositConfigBuilder()
197 | .SetEnable(true)
198 | .SetShowOnConsole(new ConsoleConfig
199 | {
200 | TurnOn = true,
201 | EnableCodeBeautification = false
202 | })
203 | .SetSaveToFile(new FileConfig
204 | {
205 | TurnOn = true,
206 | Path = tempPath,
207 | Filename = filename
208 | })
209 | .Build();
210 |
211 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config))
212 | {
213 | InnerHandler = new FakeHttpMessageHandler()
214 | };
215 |
216 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
217 |
218 | var sw = new StringWriter();
219 | var originalOut = Console.Out;
220 | var filePath = Path.Combine(tempPath.TrimEnd(Path.DirectorySeparatorChar), filename + ".curl");
221 |
222 | try
223 | {
224 | if (File.Exists(filePath))
225 | {
226 | File.Delete(filePath);
227 | }
228 |
229 | Console.SetOut(sw);
230 |
231 | // Act
232 | using var invoker = new HttpMessageInvoker(handler);
233 | var response = await invoker.SendAsync(request, CancellationToken.None);
234 |
235 | // Assert
236 | response.Should().NotBeNull();
237 | response.StatusCode.Should().Be(HttpStatusCode.OK);
238 |
239 | var output = sw.ToString();
240 | output.Should().Contain("curl");
241 |
242 | response.Should().NotBeNull();
243 | response.StatusCode.Should().Be(HttpStatusCode.OK);
244 |
245 | File.Exists(filePath).Should().BeTrue();
246 | var content = File.ReadAllText(filePath);
247 | content.Should().Contain("curl");
248 | }
249 | finally
250 | {
251 | Console.SetOut(originalOut);
252 | if (File.Exists(filePath))
253 | {
254 | File.Delete(filePath);
255 | }
256 | }
257 | }
258 |
259 | [Fact]
260 | public async Task CurlGeneratorHttpMessageHandler_LogsToILogger_When_SendToLogger_TurnOn()
261 | {
262 | // Arrange
263 | var logger = new FakeLogger();
264 | var config = new CompositConfigBuilder()
265 | .SetEnable(true)
266 | .SetSendToLogger(new LoggerConfig
267 | {
268 | TurnOn = true,
269 | LogLevel = Microsoft.Extensions.Logging.LogLevel.Debug
270 | })
271 | .Build();
272 |
273 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config), logger)
274 | {
275 | InnerHandler = new FakeHttpMessageHandler()
276 | };
277 |
278 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
279 |
280 | // Act
281 | using var invoker = new HttpMessageInvoker(handler);
282 | var response = await invoker.SendAsync(request, CancellationToken.None);
283 |
284 | // Assert
285 | response.Should().NotBeNull();
286 | response.StatusCode.Should().Be(HttpStatusCode.OK);
287 |
288 | logger.LoggedMessages.Should().HaveCount(1);
289 | logger.LoggedMessages[0].Level.Should().Be(Microsoft.Extensions.Logging.LogLevel.Debug);
290 | logger.LoggedMessages[0].Message.Should().StartWith("curl");
291 | }
292 |
293 | [Fact]
294 | public async Task CurlGeneratorHttpMessageHandler_DoesNotLog_When_Logger_IsNull()
295 | {
296 | // Arrange
297 | var config = new CompositConfigBuilder()
298 | .SetEnable(true)
299 | .SetSendToLogger(new LoggerConfig
300 | {
301 | TurnOn = true,
302 | LogLevel = Microsoft.Extensions.Logging.LogLevel.Debug
303 | })
304 | .Build();
305 |
306 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config), logger: null)
307 | {
308 | InnerHandler = new FakeHttpMessageHandler()
309 | };
310 |
311 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
312 |
313 | // Act
314 | using var invoker = new HttpMessageInvoker(handler);
315 | var response = await invoker.SendAsync(request, CancellationToken.None);
316 |
317 | // Assert
318 | response.Should().NotBeNull();
319 | response.StatusCode.Should().Be(HttpStatusCode.OK);
320 | }
321 |
322 | [Fact]
323 | public async Task CurlGeneratorHttpMessageHandler_DoesNotLog_When_SendToLogger_TurnOff()
324 | {
325 | // Arrange
326 | var logger = new FakeLogger();
327 | var config = new CompositConfigBuilder()
328 | .SetEnable(true)
329 | .SetSendToLogger(new LoggerConfig
330 | {
331 | TurnOn = false,
332 | LogLevel = Microsoft.Extensions.Logging.LogLevel.Debug
333 | })
334 | .Build();
335 |
336 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config), logger)
337 | {
338 | InnerHandler = new FakeHttpMessageHandler()
339 | };
340 |
341 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
342 |
343 | // Act
344 | using var invoker = new HttpMessageInvoker(handler);
345 | var response = await invoker.SendAsync(request, CancellationToken.None);
346 |
347 | // Assert
348 | response.Should().NotBeNull();
349 | response.StatusCode.Should().Be(HttpStatusCode.OK);
350 |
351 | logger.LoggedMessages.Should().BeEmpty();
352 | }
353 |
354 | [Fact]
355 | public async Task CurlGeneratorHttpMessageHandler_DoesNotLog_When_SendToLogger_IsNull()
356 | {
357 | // Arrange
358 | var logger = new FakeLogger();
359 | var config = new CompositConfigBuilder()
360 | .SetEnable(true)
361 | .SetSendToLogger(null)
362 | .Build();
363 |
364 | var handler = new CurlGeneratorHttpMessageHandler(new FakeOptionsMonitor(config), logger)
365 | {
366 | InnerHandler = new FakeHttpMessageHandler()
367 | };
368 |
369 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test");
370 |
371 | // Act
372 | using var invoker = new HttpMessageInvoker(handler);
373 | var response = await invoker.SendAsync(request, CancellationToken.None);
374 |
375 | // Assert
376 | response.Should().NotBeNull();
377 | response.StatusCode.Should().Be(HttpStatusCode.OK);
378 |
379 | logger.LoggedMessages.Should().BeEmpty();
380 | }
381 | }
382 |
--------------------------------------------------------------------------------
/tests/HttpRequestMessageToCurlTest/UnitTest/MediaTypes/Json/SuccessCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using FluentAssertions;
4 | using HttpClientToCurl.Builder;
5 | using Microsoft.AspNetCore.WebUtilities;
6 | using Xunit;
7 |
8 | namespace HttpRequestMessageToCurlTest.UnitTest.MediaTypes.Json;
9 |
10 | public class SuccessCurlGeneratorTests
11 | {
12 | [Fact]
13 | public void GenerateCurl_For_PostMethod()
14 | {
15 | // Arrange
16 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
17 |
18 | var requestUri = "api/test";
19 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
20 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
21 |
22 | var baseAddress = new Uri("http://localhost:1213/v1/");
23 |
24 | // Act
25 | string script = Generator.GenerateCurl(
26 | httpRequestMessage,
27 | baseAddress,
28 | null);
29 |
30 | // Assert
31 | script.Should().NotBeNullOrEmpty();
32 | script.Should().StartWith("curl -X POST");
33 | script.Trim().Should()
34 | .BeEquivalentTo(
35 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
36 | }
37 |
38 | [Fact]
39 | public void GenerateCurl_With_ContentLength_For_PostMethod()
40 | {
41 | // Arrange
42 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
43 |
44 | var requestUri = "api/test";
45 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
46 | httpRequestMessage.Headers.Add("Authorization", "Bearer f69406a4-6b62-4734-a8dc-158f0fc308ab");
47 | httpRequestMessage.Content.Headers.Add("Content-Length", "123");
48 |
49 | var baseAddress = new Uri("http://localhost:1213/v1/");
50 |
51 | // Act
52 | string script = Generator.GenerateCurl(
53 | httpRequestMessage,
54 | baseAddress,
55 | null);
56 |
57 | // Assert
58 | script.Should().NotBeNullOrEmpty();
59 | script.Should().StartWith("curl -X POST");
60 | script.Trim().Should()
61 | .BeEquivalentTo(
62 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer f69406a4-6b62-4734-a8dc-158f0fc308ab' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
63 | }
64 |
65 | [Fact]
66 | public void GenerateCurl_With_QueryString_For_PostMethod()
67 | {
68 | // Arrange
69 | string requestBody = /*lang=json,strict*/ @"{""name"":""amin"",""requestId"":10001000,""amount"":10000}";
70 |
71 | var queryString = new Dictionary { { "id", "12" }, { "name", "Morten Sjøgren" }, { "nationalCode", "123-456-7890" } };
72 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
73 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
74 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
75 |
76 | var baseAddress = new Uri("http://localhost:1213/v1/");
77 |
78 | // Act
79 | string script = Generator.GenerateCurl(
80 | httpRequestMessage,
81 | baseAddress,
82 | null);
83 |
84 | // Assert
85 |
86 | script.Should().NotBeNullOrEmpty();
87 | script.Should().StartWith("curl -X POST");
88 | script.Trim().Should()
89 | .BeEquivalentTo(
90 | @"curl -X POST 'http://localhost:1213/v1/api/test?id=12&name=Morten%20Sj%C3%B8gren&nationalCode=123-456-7890' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""amin"",""requestId"":10001000,""amount"":10000}'");
91 | }
92 |
93 | [Fact]
94 | public void GenerateCurl_UrlEncoded_For_PostMethod()
95 | {
96 | // Arrange
97 | string requestBody = /*lang=json,strict*/ @"{""name"":""justin"",""requestId"":10001026,""amount"":26000}";
98 |
99 | var requestUri = "api/test";
100 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
101 | {
102 | Content = new FormUrlEncodedContent(new[]
103 | {
104 | new KeyValuePair("session", "703438f3-16ad-4ba5-b923-8f72cd0f2db9"), new KeyValuePair("payload", requestBody),
105 | })
106 | };
107 |
108 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
109 |
110 | var baseAddress = new Uri("http://localhost:1213/v1/");
111 |
112 | // Act
113 | string script = Generator.GenerateCurl(
114 | httpRequestMessage,
115 | baseAddress,
116 | null);
117 |
118 | // Assert
119 | script.Should().NotBeNullOrEmpty();
120 | script.Should().StartWith("curl -X POST");
121 | script.Trim().Should()
122 | .BeEquivalentTo(
123 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/x-www-form-urlencoded' -d 'session=703438f3-16ad-4ba5-b923-8f72cd0f2db9' -d 'payload={""name"":""justin"",""requestId"":10001026,""amount"":26000}'");
124 | }
125 |
126 | [Fact]
127 | public void GenerateCurl_Without_RequestBody_For_PostMethod()
128 | {
129 | // Arrange
130 | var requestUri = "api/test";
131 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, "application/json") };
132 | httpRequestMessage.Headers.Add("Authorization", "Bearer c332e9a1-1e0e-44c2-b819-b0e7e8ff7d45");
133 |
134 | var baseAddress = new Uri("http://localhost:1213/v1/");
135 |
136 | // Act
137 | string script = Generator.GenerateCurl(
138 | httpRequestMessage,
139 | baseAddress,
140 | null);
141 |
142 | // Assert
143 | script.Should().NotBeNullOrEmpty();
144 | script.Should().StartWith("curl -X POST");
145 | script.Trim().Should()
146 | .BeEquivalentTo(
147 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer c332e9a1-1e0e-44c2-b819-b0e7e8ff7d45' -H 'Content-Type: application/json; charset=utf-8' -d ''");
148 | }
149 |
150 | [Fact]
151 | public void GenerateCurl_Without_Content_For_PostMethod()
152 | {
153 | // Arrange
154 | var requestUri = "api/test";
155 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = null };
156 | httpRequestMessage.Headers.Add("Authorization", "Bearer 56bfa7a0-0541-4d71-9efc-8b28219ac31a");
157 |
158 | var baseAddress = new Uri("http://localhost:1213/v1/");
159 |
160 | // Act
161 | string script = Generator.GenerateCurl(
162 | httpRequestMessage,
163 | baseAddress,
164 | null);
165 |
166 | // Assert
167 | script.Should().NotBeNullOrEmpty();
168 | script.Should().StartWith("curl -X POST");
169 | script.Trim().Should()
170 | .BeEquivalentTo(
171 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 56bfa7a0-0541-4d71-9efc-8b28219ac31a' -d ''");
172 | }
173 |
174 | [Fact]
175 | public void GenerateCurl_When_Invalid_JsonBody_PostMethod()
176 | {
177 | // Arrange
178 | string requestBody = @"""name"":""steven"",""requestId"":10001005,""amount"":60000";
179 |
180 | var requestUri = "api/test";
181 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
182 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
183 |
184 | var baseAddress = new Uri("http://localhost:1213/v1/");
185 |
186 | // Act
187 | string script = Generator.GenerateCurl(
188 | httpRequestMessage,
189 | baseAddress,
190 | null);
191 |
192 | // Assert
193 | script.Should().NotBeNullOrEmpty();
194 | script.Should().StartWith("curl -X POST");
195 | script.Trim().Should()
196 | .BeEquivalentTo(
197 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '""name"":""steven"",""requestId"":10001005,""amount"":60000'");
198 | }
199 |
200 | [Fact]
201 | public void GenerateCurl_When_BaseAddress_Is_Null_PostMethod()
202 | {
203 | // Arrange
204 | string requestBody = /*lang=json,strict*/ @"{""name"":""nancy"",""requestId"":10001006,""amount"":70000}";
205 |
206 | var requestUri = "api/test";
207 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
208 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
209 |
210 | Uri? baseAddress = null;
211 |
212 | // Act
213 | string script = Generator.GenerateCurl(
214 | httpRequestMessage,
215 | baseAddress,
216 | null);
217 |
218 | // Assert
219 | script.Should().NotBeNullOrEmpty();
220 | script.Should().StartWith("curl -X POST");
221 | script.Trim().Should()
222 | .BeEquivalentTo(
223 | @"curl -X POST 'api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""nancy"",""requestId"":10001006,""amount"":70000}'");
224 | }
225 |
226 | [Fact]
227 | public void GenerateCurl_For_GetMethod()
228 | {
229 | // Arrange
230 | var requestUri = "api/test";
231 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
232 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
233 |
234 | var baseAddress = new Uri("http://localhost:1213/v1/");
235 |
236 | // Act
237 | string script = Generator.GenerateCurl(
238 | httpRequestMessage,
239 | baseAddress,
240 | null);
241 |
242 | // Assert
243 | script.Should().NotBeNullOrEmpty();
244 | script.Should().StartWith("curl");
245 | script.Trim().Should()
246 | .BeEquivalentTo(
247 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
248 | }
249 |
250 | [Fact]
251 | public void GenerateCurl_With_QueryString_For_GetMethod()
252 | {
253 | // Arrange
254 | var queryString = new Dictionary { { "id", "12" } };
255 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
256 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
257 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
258 |
259 | var baseAddress = new Uri("http://localhost:1213/v1/");
260 |
261 | // Act
262 | string script = Generator.GenerateCurl(
263 | httpRequestMessage,
264 | baseAddress,
265 | null);
266 |
267 | // Assert
268 | script.Should().NotBeNullOrEmpty();
269 | script.Should().StartWith("curl");
270 | script.Trim().Should()
271 | .BeEquivalentTo(
272 | @"curl 'http://localhost:1213/v1/api/test?id=12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
273 | }
274 |
275 | [Fact]
276 | public void GenerateCurl_For_PutMethod()
277 | {
278 | // Arrange
279 | string requestBody = /*lang=json,strict*/ @"{""name"":""reza"",""requestId"":10001002,""amount"":30000}";
280 |
281 | var requestUri = "api/test";
282 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
283 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
284 |
285 | var baseAddress = new Uri("http://localhost:1213/v1/");
286 |
287 | // Act
288 | string script = Generator.GenerateCurl(
289 | httpRequestMessage,
290 | baseAddress,
291 | null);
292 |
293 | // Assert
294 | script.Should().NotBeNullOrEmpty();
295 | script.Should().StartWith("curl -X PUT");
296 | script.Trim().Should()
297 | .BeEquivalentTo(
298 | @"curl -X PUT 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""reza"",""requestId"":10001002,""amount"":30000}'");
299 | }
300 |
301 | [Fact]
302 | public void GenerateCurl_For_PatchMethod()
303 | {
304 | // Arrange
305 | string requestBody = /*lang=json,strict*/ @"{""name"":""hamed"",""requestId"":10001003,""amount"":40000}";
306 |
307 | var requestUri = "api/test";
308 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Patch, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
309 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
310 |
311 | var baseAddress = new Uri("http://localhost:1213/v1/");
312 |
313 | // Act
314 | string script = Generator.GenerateCurl(
315 | httpRequestMessage,
316 | baseAddress,
317 | null);
318 |
319 | // Assert
320 | script.Should().NotBeNullOrEmpty();
321 | script.Should().StartWith("curl -X PATCH");
322 | script.Trim().Should()
323 | .BeEquivalentTo(
324 | @"curl -X PATCH 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""hamed"",""requestId"":10001003,""amount"":40000}'");
325 | }
326 |
327 | [Fact]
328 | public void GenerateCurl_For_DeleteMethod()
329 | {
330 | // Arrange
331 | var id = 12;
332 | var requestUri = $"api/test/{id}";
333 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri)
334 | {
335 | Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json)
336 | };
337 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
338 |
339 | var baseAddress = new Uri("http://localhost:1213/v1/");
340 |
341 | // Act
342 | string script = Generator.GenerateCurl(
343 | httpRequestMessage,
344 | baseAddress,
345 | null);
346 |
347 | // Assert
348 | script.Should().NotBeNullOrEmpty();
349 | script.Should().StartWith("curl -X DELETE");
350 | script.Trim().Should()
351 | .BeEquivalentTo(
352 | @"curl -X DELETE 'http://localhost:1213/v1/api/test/12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
353 | }
354 | }
355 |
--------------------------------------------------------------------------------
/tests/HttpClientToCurlTest/UnitTest/MediaTypes/Json/SuccessCurlGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using FluentAssertions;
4 | using HttpClientToCurl.Builder;
5 | using Microsoft.AspNetCore.WebUtilities;
6 | using Xunit;
7 |
8 | namespace HttpClientToCurlTest.UnitTest.MediaTypes.Json;
9 |
10 | public class SuccessCurlGeneratorTests
11 | {
12 | [Fact]
13 | public void GenerateCurl_For_PostMethod()
14 | {
15 | // Arrange
16 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
17 |
18 | var requestUri = "api/test";
19 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
20 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
21 |
22 | using var httpClient = new HttpClient();
23 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
24 |
25 | // Act
26 | string script = Generator.GenerateCurl(
27 | httpClient,
28 | httpRequestMessage,
29 | null);
30 |
31 | // Assert
32 | script.Should().NotBeNullOrEmpty();
33 | script.Should().StartWith("curl -X POST");
34 | script.Trim().Should()
35 | .BeEquivalentTo(
36 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
37 | }
38 |
39 | [Fact]
40 | public void GenerateCurl_With_ContentLength_For_PostMethod()
41 | {
42 | // Arrange
43 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
44 |
45 | var requestUri = "api/test";
46 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
47 | httpRequestMessage.Headers.Add("Authorization", "Bearer f69406a4-6b62-4734-a8dc-158f0fc308ab");
48 | httpRequestMessage.Content.Headers.Add("Content-Length", "123");
49 |
50 | using var httpClient = new HttpClient();
51 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
52 |
53 | // Act
54 | string script = Generator.GenerateCurl(
55 | httpClient,
56 | httpRequestMessage,
57 | null);
58 |
59 | // Assert
60 | script.Should().NotBeNullOrEmpty();
61 | script.Should().StartWith("curl -X POST");
62 | script.Trim().Should()
63 | .BeEquivalentTo(
64 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer f69406a4-6b62-4734-a8dc-158f0fc308ab' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
65 | }
66 |
67 | [Fact]
68 | public void GenerateCurl_With_QueryString_For_PostMethod()
69 | {
70 | // Arrange
71 | string requestBody = /*lang=json,strict*/ @"{""name"":""amin"",""requestId"":10001000,""amount"":10000}";
72 |
73 | var queryString = new Dictionary { { "id", "12" }, { "name", "Morten Sjøgren" }, { "nationalCode", "123-456-7890" } };
74 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
75 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
76 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
77 |
78 | using var httpClient = new HttpClient();
79 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
80 |
81 | // Act
82 | string script = Generator.GenerateCurl(
83 | httpClient,
84 | httpRequestMessage,
85 | null);
86 |
87 | // Assert
88 |
89 | script.Should().NotBeNullOrEmpty();
90 | script.Should().StartWith("curl -X POST");
91 | script.Trim().Should()
92 | .BeEquivalentTo(
93 | @"curl -X POST 'http://localhost:1213/v1/api/test?id=12&name=Morten%20Sj%C3%B8gren&nationalCode=123-456-7890' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""amin"",""requestId"":10001000,""amount"":10000}'");
94 | }
95 |
96 | [Fact]
97 | public void GenerateCurl_UrlEncoded_For_PostMethod()
98 | {
99 | // Arrange
100 | string requestBody = /*lang=json,strict*/ @"{""name"":""justin"",""requestId"":10001026,""amount"":26000}";
101 |
102 | var requestUri = "api/test";
103 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
104 | {
105 | Content = new FormUrlEncodedContent(new[]
106 | {
107 | new KeyValuePair("session", "703438f3-16ad-4ba5-b923-8f72cd0f2db9"), new KeyValuePair("payload", requestBody),
108 | })
109 | };
110 |
111 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
112 |
113 | using var httpClient = new HttpClient();
114 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
115 |
116 | // Act
117 | string script = Generator.GenerateCurl(
118 | httpClient,
119 | httpRequestMessage,
120 | null);
121 |
122 | // Assert
123 | script.Should().NotBeNullOrEmpty();
124 | script.Should().StartWith("curl -X POST");
125 | script.Trim().Should()
126 | .BeEquivalentTo(
127 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/x-www-form-urlencoded' -d 'session=703438f3-16ad-4ba5-b923-8f72cd0f2db9' -d 'payload={""name"":""justin"",""requestId"":10001026,""amount"":26000}'");
128 | }
129 |
130 | [Fact]
131 | public void GenerateCurl_Without_RequestBody_For_PostMethod()
132 | {
133 | // Arrange
134 | var requestUri = "api/test";
135 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, "application/json") };
136 | httpRequestMessage.Headers.Add("Authorization", "Bearer c332e9a1-1e0e-44c2-b819-b0e7e8ff7d45");
137 |
138 | using var httpClient = new HttpClient();
139 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
140 |
141 | // Act
142 | string script = Generator.GenerateCurl(
143 | httpClient,
144 | httpRequestMessage,
145 | null);
146 |
147 | // Assert
148 | script.Should().NotBeNullOrEmpty();
149 | script.Should().StartWith("curl -X POST");
150 | script.Trim().Should()
151 | .BeEquivalentTo(
152 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer c332e9a1-1e0e-44c2-b819-b0e7e8ff7d45' -H 'Content-Type: application/json; charset=utf-8' -d ''");
153 | }
154 |
155 | [Fact]
156 | public void GenerateCurl_Without_Content_For_PostMethod()
157 | {
158 | // Arrange
159 | var requestUri = "api/test";
160 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = null };
161 | httpRequestMessage.Headers.Add("Authorization", "Bearer 56bfa7a0-0541-4d71-9efc-8b28219ac31a");
162 |
163 | using var httpClient = new HttpClient();
164 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
165 |
166 | // Act
167 | string script = Generator.GenerateCurl(
168 | httpClient,
169 | httpRequestMessage,
170 | null);
171 |
172 | // Assert
173 | script.Should().NotBeNullOrEmpty();
174 | script.Should().StartWith("curl -X POST");
175 | script.Trim().Should()
176 | .BeEquivalentTo(
177 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 56bfa7a0-0541-4d71-9efc-8b28219ac31a' -d ''");
178 | }
179 |
180 | [Fact]
181 | public void GenerateCurl_When_Invalid_JsonBody_PostMethod()
182 | {
183 | // Arrange
184 | string requestBody = @"""name"":""steven"",""requestId"":10001005,""amount"":60000";
185 |
186 | var requestUri = "api/test";
187 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
188 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
189 |
190 | using var httpClient = new HttpClient();
191 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
192 |
193 | // Act
194 | string script = Generator.GenerateCurl(
195 | httpClient,
196 | httpRequestMessage,
197 | null);
198 |
199 | // Assert
200 | script.Should().NotBeNullOrEmpty();
201 | script.Should().StartWith("curl -X POST");
202 | script.Trim().Should()
203 | .BeEquivalentTo(
204 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '""name"":""steven"",""requestId"":10001005,""amount"":60000'");
205 | }
206 |
207 | [Fact]
208 | public void GenerateCurl_When_BaseAddress_Is_Null_PostMethod()
209 | {
210 | // Arrange
211 | string requestBody = /*lang=json,strict*/ @"{""name"":""nancy"",""requestId"":10001006,""amount"":70000}";
212 |
213 | var requestUri = "api/test";
214 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
215 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
216 |
217 | using var httpClient = new HttpClient();
218 | httpClient.BaseAddress = null;
219 |
220 | // Act
221 | string script = Generator.GenerateCurl(
222 | httpClient,
223 | httpRequestMessage,
224 | null);
225 |
226 | // Assert
227 | script.Should().NotBeNullOrEmpty();
228 | script.Should().StartWith("curl -X POST");
229 | script.Trim().Should()
230 | .BeEquivalentTo(
231 | @"curl -X POST 'api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""nancy"",""requestId"":10001006,""amount"":70000}'");
232 | }
233 |
234 | [Fact]
235 | public void GenerateCurl_For_GetMethod()
236 | {
237 | // Arrange
238 | var requestUri = "api/test";
239 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
240 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
241 |
242 | using var httpClient = new HttpClient();
243 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
244 |
245 | // Act
246 | string script = Generator.GenerateCurl(
247 | httpClient,
248 | httpRequestMessage,
249 | null);
250 |
251 | // Assert
252 | script.Should().NotBeNullOrEmpty();
253 | script.Should().StartWith("curl");
254 | script.Trim().Should()
255 | .BeEquivalentTo(
256 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
257 | }
258 |
259 | [Fact]
260 | public void GenerateCurl_With_QueryString_For_GetMethod()
261 | {
262 | // Arrange
263 | var queryString = new Dictionary { { "id", "12" } };
264 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
265 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
266 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
267 |
268 | using var httpClient = new HttpClient();
269 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
270 |
271 | // Act
272 | string script = Generator.GenerateCurl(
273 | httpClient,
274 | httpRequestMessage,
275 | null);
276 |
277 | // Assert
278 | script.Should().NotBeNullOrEmpty();
279 | script.Should().StartWith("curl");
280 | script.Trim().Should()
281 | .BeEquivalentTo(
282 | @"curl 'http://localhost:1213/v1/api/test?id=12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
283 | }
284 |
285 | [Fact]
286 | public void GenerateCurl_For_PutMethod()
287 | {
288 | // Arrange
289 | string requestBody = /*lang=json,strict*/ @"{""name"":""reza"",""requestId"":10001002,""amount"":30000}";
290 |
291 | var requestUri = "api/test";
292 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
293 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
294 |
295 | using var httpClient = new HttpClient();
296 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
297 |
298 | // Act
299 | string script = Generator.GenerateCurl(
300 | httpClient,
301 | httpRequestMessage,
302 | null);
303 |
304 | // Assert
305 | script.Should().NotBeNullOrEmpty();
306 | script.Should().StartWith("curl -X PUT");
307 | script.Trim().Should()
308 | .BeEquivalentTo(
309 | @"curl -X PUT 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""reza"",""requestId"":10001002,""amount"":30000}'");
310 | }
311 |
312 | [Fact]
313 | public void GenerateCurl_For_PatchMethod()
314 | {
315 | // Arrange
316 | string requestBody = /*lang=json,strict*/ @"{""name"":""hamed"",""requestId"":10001003,""amount"":40000}";
317 |
318 | var requestUri = "api/test";
319 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Patch, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
320 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
321 |
322 | using var httpClient = new HttpClient();
323 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
324 |
325 | // Act
326 | string script = Generator.GenerateCurl(
327 | httpClient,
328 | httpRequestMessage,
329 | null);
330 |
331 | // Assert
332 | script.Should().NotBeNullOrEmpty();
333 | script.Should().StartWith("curl -X PATCH");
334 | script.Trim().Should()
335 | .BeEquivalentTo(
336 | @"curl -X PATCH 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""hamed"",""requestId"":10001003,""amount"":40000}'");
337 | }
338 |
339 | [Fact]
340 | public void GenerateCurl_For_DeleteMethod()
341 | {
342 | // Arrange
343 | var id = 12;
344 | var requestUri = $"api/test/{id}";
345 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri)
346 | {
347 | Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json)
348 | };
349 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
350 |
351 | using var httpClient = new HttpClient();
352 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
353 |
354 | // Act
355 | string script = Generator.GenerateCurl(
356 | httpClient,
357 | httpRequestMessage,
358 | null);
359 |
360 | // Assert
361 | script.Should().NotBeNullOrEmpty();
362 | script.Should().StartWith("curl -X DELETE");
363 | script.Trim().Should()
364 | .BeEquivalentTo(
365 | @"curl -X DELETE 'http://localhost:1213/v1/api/test/12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/tests/HttpClientToCurlTest/FunctionalTest/SuccessScenariosTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Headers;
2 | using System.Net.Http.Json;
3 | using System.Net.Mime;
4 | using System.Text;
5 | using FluentAssertions;
6 | using HttpClientToCurl.Extensions;
7 | using HttpClientToCurl.Utility;
8 | using Microsoft.AspNetCore.WebUtilities;
9 | using Xunit;
10 |
11 | namespace HttpClientToCurlTest.FunctionalTest;
12 |
13 | public class SuccessScenariosTests
14 | {
15 | #region :: GenerateCurlInString For Post Method ::
16 |
17 | [Fact]
18 | public void Success_GenerateCurlInString_For_PostMethod()
19 | {
20 | // Arrange
21 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
22 |
23 | var requestUri = "api/test";
24 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
25 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
26 |
27 | using var httpClient = new HttpClient();
28 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
29 |
30 | // Act
31 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
32 |
33 | // Assert
34 | curlResult.Should().NotBeNullOrEmpty();
35 | curlResult.Should().StartWith("curl -X POST");
36 | curlResult.Trim().Should()
37 | .BeEquivalentTo(
38 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
39 | }
40 |
41 | [Fact]
42 | public void Success_GenerateCurlInString_With_RequestUri_TypeOf_Uri_For_PostMethod()
43 | {
44 | // Arrange
45 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
46 |
47 | var requestUri = Helpers.CreateUri("api/test");
48 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
49 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
50 |
51 | using var httpClient = new HttpClient();
52 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
53 |
54 | // Act
55 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
56 |
57 | // Assert
58 | curlResult.Should().NotBeNullOrEmpty();
59 | curlResult.Should().StartWith("curl -X POST");
60 | curlResult.Trim().Should()
61 | .BeEquivalentTo(
62 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
63 | }
64 |
65 | [Fact]
66 | public void GenerateCurl_When_Set_RequestUri_Inside_HttpRequestMessage_For_PostMethod()
67 | {
68 | // Arrange
69 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
70 |
71 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "api/test") { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
72 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
73 |
74 | using var httpClient = new HttpClient();
75 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
76 |
77 | // Act
78 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
79 |
80 | // Assert
81 | curlResult.Should().NotBeNullOrEmpty();
82 | curlResult.Should().StartWith("curl -X POST");
83 | curlResult.Trim().Should()
84 | .BeEquivalentTo(
85 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
86 | }
87 |
88 | [Fact]
89 | public void Success_GenerateCurlInString_When_RequestUri_Is_Null_For_PostMethod()
90 | {
91 | // Arrange
92 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
93 |
94 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, string.Empty) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
95 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
96 |
97 | using var httpClient = new HttpClient();
98 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
99 |
100 | // Act
101 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
102 |
103 | // Assert
104 | curlResult.Should().NotBeNullOrEmpty();
105 | curlResult.Should().StartWith("curl -X POST");
106 | curlResult.Trim().Should()
107 | .BeEquivalentTo(
108 | @"curl -X POST 'http://localhost:1213/v1/' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
109 | }
110 |
111 | [Fact]
112 | public void Success_GenerateCurlInString_When_RequestBody_Is_Null_For_PostMethod()
113 | {
114 | // Arrange
115 | var requestUri = "api/test";
116 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
117 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
118 |
119 | using var httpClient = new HttpClient();
120 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
121 |
122 | // Act
123 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
124 |
125 | // Assert
126 | curlResult.Should().NotBeNullOrEmpty();
127 | curlResult.Should().StartWith("curl -X POST");
128 | curlResult.Trim().Should()
129 | .BeEquivalentTo(
130 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d ''");
131 | }
132 |
133 | [Fact]
134 | public void Success_GenerateCurlInString_When_HttpContent_Is_Null_For_PostMethod()
135 | {
136 | // Arrange
137 | var requestUri = "api/test";
138 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
139 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
140 |
141 | using var httpClient = new HttpClient();
142 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
143 |
144 | // Act
145 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
146 |
147 | // Assert
148 | curlResult.Should().NotBeNullOrEmpty();
149 | curlResult.Should().StartWith("curl -X POST");
150 | curlResult.Trim().Should().BeEquivalentTo(@"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -d ''");
151 | }
152 |
153 | [Fact]
154 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_For_PostMethod()
155 | {
156 | // Arrange
157 | var requestObject = new { name = "sara", requestId = 10001001, amount = 20000, };
158 |
159 | JsonContent jsonContent = JsonContent.Create(requestObject);
160 |
161 | var requestUri = "api/test";
162 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
163 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
164 |
165 | using var httpClient = new HttpClient();
166 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
167 |
168 | // Act
169 | string curlResult = httpClient.GenerateCurlInString(
170 | HttpMethod.Post, requestUri, httpRequestHeaders, jsonContent);
171 |
172 | // Assert
173 | curlResult.Should().NotBeNullOrEmpty();
174 | curlResult.Should().StartWith("curl -X POST");
175 | curlResult.Trim().Should()
176 | .BeEquivalentTo(
177 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
178 | }
179 |
180 | [Fact]
181 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_With_RequestUri_Typeof_Uri_For_PostMethod()
182 | {
183 | // Arrange
184 | var requestObject = new { name = "sara", requestId = 10001001, amount = 20000, };
185 |
186 | JsonContent jsonContent = JsonContent.Create(requestObject);
187 |
188 | var requestUri = Helpers.CreateUri("api/test");
189 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
190 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
191 |
192 | using var httpClient = new HttpClient();
193 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
194 |
195 | // Act
196 | string curlResult = httpClient.GenerateCurlInString(
197 | HttpMethod.Post, requestUri, httpRequestHeaders, jsonContent);
198 |
199 | // Assert
200 | curlResult.Should().NotBeNullOrEmpty();
201 | curlResult.Should().StartWith("curl -X POST");
202 | curlResult.Trim().Should()
203 | .BeEquivalentTo(
204 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
205 | }
206 |
207 | [Fact]
208 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_And_Body_Is_Null_For_PostMethod()
209 | {
210 | // Arrange
211 | var requestUri = "api/test";
212 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
213 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
214 |
215 | using var httpClient = new HttpClient();
216 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
217 |
218 | // Act
219 | string curlResult = httpClient.GenerateCurlInString(
220 | HttpMethod.Post, requestUri, httpRequestHeaders);
221 |
222 | // Assert
223 | curlResult.Should().NotBeNullOrEmpty();
224 | curlResult.Should().StartWith("curl -X POST");
225 | curlResult.Trim().Should().BeEquivalentTo(@"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -d ''");
226 | }
227 |
228 | [Fact]
229 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_And_RequestUri_Is_Null_For_PostMethod()
230 | {
231 | // Arrange
232 | var requestObject = new { name = "sara", requestId = 10001001, amount = 20000, };
233 |
234 | JsonContent jsonContent = JsonContent.Create(requestObject);
235 |
236 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
237 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
238 |
239 | using var httpClient = new HttpClient();
240 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
241 |
242 | // Act
243 | string curlResult = httpClient.GenerateCurlInString(
244 | httpMethod: HttpMethod.Post, httpRequestHeaders: httpRequestHeaders, httpContent: jsonContent, requestUri: string.Empty);
245 |
246 | // Assert
247 | curlResult.Should().NotBeNullOrEmpty();
248 | curlResult.Should().StartWith("curl -X POST");
249 | curlResult.Trim().Should()
250 | .BeEquivalentTo(
251 | @"curl -X POST 'http://localhost:1213/v1/' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
252 | }
253 |
254 | [Fact]
255 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_And_HttpRequestHeader_Is_null_For_PostMethod()
256 | {
257 | // Arrange
258 | var requestObject = new { name = "sara", requestId = 10001001, amount = 20000, };
259 |
260 | JsonContent jsonContent = JsonContent.Create(requestObject);
261 |
262 | var requestUri = "api/test";
263 |
264 | using var httpClient = new HttpClient();
265 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
266 |
267 | // Act
268 | string curlResult = httpClient.GenerateCurlInString(
269 | httpMethod: HttpMethod.Post, requestUri: requestUri, httpContent: jsonContent);
270 |
271 | // Assert
272 | curlResult.Should().NotBeNullOrEmpty();
273 | curlResult.Should().StartWith("curl -X POST");
274 | curlResult.Trim().Should()
275 | .BeEquivalentTo(
276 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
277 | }
278 |
279 | [Fact]
280 | public void Success_GenerateCurlInString_With_Multiple_Value_For_A_Header_PostMethod()
281 | {
282 | // Arrange
283 | string requestBody = /*lang=json,strict*/ @"{""name"":""sara"",""requestId"":10001001,""amount"":20000}";
284 |
285 | var requestUri = "api/test";
286 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(requestBody, Encoding.UTF8, MediaTypeNames.Application.Json) };
287 | httpRequestMessage.Headers.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
288 |
289 | List headerValues = ["_ga=GA1.1.41226618.1701506283", "mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05", "sp_ses.13cb=*"];
290 | httpRequestMessage.Headers.Add("cookie", headerValues);
291 |
292 | using var httpClient = new HttpClient();
293 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
294 |
295 | // Act
296 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
297 |
298 | // Assert
299 | curlResult.Should().NotBeNullOrEmpty();
300 | curlResult.Should().StartWith("curl -X POST");
301 | curlResult.Trim().Should()
302 | .BeEquivalentTo(
303 | @"curl -X POST 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61' -H 'Cookie: _ga=GA1.1.41226618.1701506283; mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05; sp_ses.13cb=*' -H 'Content-Type: application/json; charset=utf-8' -d '{""name"":""sara"",""requestId"":10001001,""amount"":20000}'");
304 | }
305 |
306 | #endregion
307 |
308 | #region :: GenerateCurlInString For Get Method ::
309 |
310 | [Fact]
311 | public void Success_GenerateCurlInString_For_GetMethod()
312 | {
313 | // Arrange
314 | var requestUri = "api/test";
315 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
316 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
317 |
318 | using var httpClient = new HttpClient();
319 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
320 |
321 | // Act
322 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
323 |
324 | // Assert
325 | curlResult.Should().NotBeNullOrEmpty();
326 | curlResult.Should().StartWith("curl");
327 | curlResult.Trim().Should()
328 | .BeEquivalentTo(
329 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
330 | }
331 |
332 | [Fact]
333 | public void Success_GenerateCurlInString_With_QueryString_For_GetMethod()
334 | {
335 | // Arrange
336 | var queryString = new Dictionary { { "id", "12" } };
337 | var requestUri = QueryHelpers.AddQueryString("api/test", queryString!);
338 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
339 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
340 |
341 | using var httpClient = new HttpClient();
342 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
343 |
344 | // Act
345 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
346 |
347 | // Assert
348 | curlResult.Should().NotBeNullOrEmpty();
349 | curlResult.Should().StartWith("curl");
350 | curlResult.Trim().Should()
351 | .BeEquivalentTo(
352 | @"curl 'http://localhost:1213/v1/api/test?id=12' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
353 | }
354 |
355 | [Fact]
356 | public void Success_GenerateCurlInString_When_RequestUri_Is_Null_For_GetMethod()
357 | {
358 | // Arrange
359 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, string.Empty) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
360 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
361 |
362 | using var httpClient = new HttpClient();
363 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
364 |
365 | // Act
366 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
367 |
368 | // Assert
369 | curlResult.Should().NotBeNullOrEmpty();
370 | curlResult.Should().StartWith("curl");
371 | curlResult.Trim().Should()
372 | .BeEquivalentTo(@"curl 'http://localhost:1213/v1/' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Content-Type: application/json; charset=utf-8'");
373 | }
374 |
375 | [Fact]
376 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_For_GetMethod()
377 | {
378 | // Arrange
379 | var requestUri = "api/test";
380 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
381 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
382 |
383 | using var httpClient = new HttpClient();
384 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
385 |
386 | // Act
387 | string curlResult = httpClient.GenerateCurlInString(
388 | HttpMethod.Get, requestUri, httpRequestHeaders);
389 |
390 | // Assert
391 | curlResult.Should().NotBeNullOrEmpty();
392 | curlResult.Should().StartWith("curl");
393 | curlResult.Trim().Should().BeEquivalentTo(@"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61'");
394 | }
395 |
396 | [Fact]
397 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_And_RequestUri_Is_Null_For_GetMethod()
398 | {
399 | // Arrange
400 | HttpRequestHeaders httpRequestHeaders = new HttpRequestMessage().Headers;
401 | httpRequestHeaders.Add("Authorization", "Bearer 4797c126-3f8a-454a-aff1-96c0220dae61");
402 |
403 | using var httpClient = new HttpClient();
404 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
405 |
406 | // Act
407 | string curlResult = httpClient.GenerateCurlInString(
408 | httpMethod: HttpMethod.Get, httpRequestHeaders: httpRequestHeaders);
409 |
410 | // Assert
411 | curlResult.Should().NotBeNullOrEmpty();
412 | curlResult.Should().StartWith("curl");
413 | curlResult.Trim().Should().BeEquivalentTo(@"curl 'http://localhost:1213/v1/' -H 'Authorization: Bearer 4797c126-3f8a-454a-aff1-96c0220dae61'");
414 | }
415 |
416 | [Fact]
417 | public void Success_GenerateCurlInString_Without_HttpRequestMessage_And_HttpRequestHeader_Is_null_For_GetMethod()
418 | {
419 | // Arrange
420 | var requestUri = "api/test";
421 |
422 | using var httpClient = new HttpClient();
423 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
424 |
425 | // Act
426 | string curlResult = httpClient.GenerateCurlInString(
427 | HttpMethod.Get, requestUri);
428 |
429 | // Assert
430 | curlResult.Should().NotBeNullOrEmpty();
431 | curlResult.Should().StartWith("curl");
432 | curlResult.Trim().Should().BeEquivalentTo(@"curl 'http://localhost:1213/v1/api/test'");
433 | }
434 |
435 | [Fact]
436 | public void Success_GenerateCurlInString_With_Multiple_Value_For_A_Header_GetMethod()
437 | {
438 | // Arrange
439 | var requestUri = "api/test";
440 | var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri) { Content = new StringContent(string.Empty, Encoding.UTF8, MediaTypeNames.Application.Json) };
441 | httpRequestMessage.Headers.Add("Authorization", "Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9");
442 |
443 | List headerValues = ["_ga=GA1.1.41226618.1701506283", "mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05", "sp_ses.13cb=*"];
444 | httpRequestMessage.Headers.Add("cookie", headerValues);
445 |
446 | using var httpClient = new HttpClient();
447 | httpClient.BaseAddress = new Uri("http://localhost:1213/v1/");
448 |
449 | // Act
450 | string curlResult = httpClient.GenerateCurlInString(httpRequestMessage);
451 |
452 | // Assert
453 | curlResult.Should().NotBeNullOrEmpty();
454 | curlResult.Should().StartWith("curl");
455 | curlResult.Trim().Should()
456 | .BeEquivalentTo(
457 | @"curl 'http://localhost:1213/v1/api/test' -H 'Authorization: Bearer 703438f3-16ad-4ba5-b923-8f72cd0f2db9' -H 'Cookie: _ga=GA1.1.41226618.1701506283; mywebsite-sp=cbf42587-7ec5-4179-aac5-cbc9ae6fbf05; sp_ses.13cb=*' -H 'Content-Type: application/json; charset=utf-8'");
458 | }
459 |
460 | #endregion
461 | }
462 |
--------------------------------------------------------------------------------