Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
<Project>
<PropertyGroup>
<RepositoryDirectory>$(MSBuildThisFileDirectory)</RepositoryDirectory>
<BuildToolsDirectory>$(RepositoryDirectory)build\</BuildToolsDirectory>
</PropertyGroup>

<PropertyGroup>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
</PropertyGroup>

Expand Down Expand Up @@ -41,6 +36,11 @@
<NoWarn>$(NoWarn);CS8500</NoWarn>
</PropertyGroup>

<PropertyGroup>
<RepositoryDirectory>$(MSBuildThisFileDirectory)</RepositoryDirectory>
<BuildToolsDirectory>$(RepositoryDirectory)build\</BuildToolsDirectory>
</PropertyGroup>

<PropertyGroup>
<IsTestProject>$(MSBuildProjectName.Contains('Test'))</IsTestProject>
<IsCoreProject Condition="$(IsTestProject)">False</IsCoreProject>
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>

<PropertyGroup>
<CommonTags Condition="$(IsCoreProject)">$(CommonTags);.NET</CommonTags>
<CommonTags Condition="$(IsCoreProject)">$(CommonTags);fluent;.NET</CommonTags>
<PackageTags Condition="'$(PackageTags)' != ''">$(CommonTags);$(PackageTags)</PackageTags>
<PackageTags Condition="'$(PackageTags)' == ''">$(CommonTags)</PackageTags>
</PropertyGroup>
Expand Down
143 changes: 140 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,141 @@
# Fluent Framework
<div align="center">
<h1>🚀 Fluent Framework</h1>
<h3><em>A modern collection of libraries for .NET applications.</em></h3>
</div>

[Created with love in Poland by Leszek Pomianowski](https://lepo.co/) and [wonderful open-source community](https://github.com/lepoco/fluent/graphs/contributors).
Fluent is an advanced .NET framework for UI and application development.
<p align="center">
<strong>Build better .NET applications with fluent, expressive APIs across HTTP, UI, and more.</strong>
</p>

<p align="center">
<a href="https://github.com/lepoco/fluent/stargazers"><img src="https://img.shields.io/github/stars/lepoco/fluent?style=social" alt="GitHub stars"/></a>
<a href="https://github.com/lepoco/fluent/blob/main/LICENSE"><img src="https://img.shields.io/github/license/lepoco/fluent" alt="License"/></a>
<a href="https://github.com/lepoco/fluent/graphs/contributors"><img src="https://img.shields.io/github/contributors/lepoco/fluent" alt="Contributors"/></a>
</p>

<p align="center">
<a href="https://lepo.co/">Created with ❤️ in Poland by Leszek Pomianowski</a> and <a href="https://github.com/lepoco/fluent/graphs/contributors">open-source community</a>.
</p>

---

## 📦 Packages

Fluent Framework is a collection of independent packages. Use what you need.

| Package | Description | NuGet |
|---------|-------------|-------|
| [**Fluent.Client**](src/Fluent.Client) | Fluent HTTP client wrapper for clean, chainable requests | [![NuGet](https://img.shields.io/nuget/v/Fluent.Client.svg)](https://www.nuget.org/packages/Fluent.Client) |
| [**Fluent.Client.AwesomeAssertions**](src/Fluent.Client.AwesomeAssertions) | Expressive HTTP response assertions for integration tests | [![NuGet](https://img.shields.io/nuget/v/Fluent.Client.AwesomeAssertions.svg)](https://www.nuget.org/packages/Fluent.Client.AwesomeAssertions) |

> [!NOTE]
> More packages coming soon. Stay tuned!

---

## ⚡ Quick Start

### HTTP Client

```powershell
dotnet add package Fluent.Client
```

```csharp
using Fluent.Client;

var client = new HttpClient { BaseAddress = new Uri("https://api.example.com/") };

// Clean, fluent HTTP requests
var response = await client
.Authorize(token: "jwt-token")
.Post("/api/users", new { Name = "John" });
```

### Testing Assertions

```powershell
dotnet add package Fluent.Client.AwesomeAssertions
```

```csharp
using Fluent.Client.AwesomeAssertions;

// Expressive test assertions
await client
.Post("/api/users", new { Name = "John" })
.Should()
.Succeed("because valid data was provided");
```

---

## 🎯 Philosophy

Fluent Framework follows these principles:

| Principle | Description |
|-----------|-------------|
| **🧩 Modular** | Use only what you need. Each package is independent. |
| **📖 Readable** | APIs designed to read like natural language. |
| **🔧 Extensible** | Easy to extend and customize for your needs. |
| **✅ Testable** | Built with testing in mind from the ground up. |
| **🚀 Modern** | Targets latest .NET with modern C# features. |

---

## 🛠️ Building from Source

### Prerequisites

- [.NET 10 SDK](https://dotnet.microsoft.com/download) or later
- Visual Studio 2022, VS Code, or JetBrains Rider

### Build

```powershell
git clone https://github.com/lepoco/fluent.git
cd fluent
dotnet build
```

### Run Tests

```powershell
dotnet test
```

---

## 🤝 Contributing

We welcome contributions! Please see our [Contributing Guide](Contributing.md) for details.

### Ways to Contribute

- 🐛 Report bugs and issues
- 💡 Suggest new features or packages
- 📝 Improve documentation
- 🔧 Submit pull requests

---

## 👥 Maintainers

- Leszek Pomianowski ([@pomianowski](https://github.com/pomianowski))

---

## 💬 Support

- 📖 [Documentation](docs/)
- 🐛 [Issue Tracker](https://github.com/lepoco/fluent/issues)
- 💬 [Discussions](https://github.com/lepoco/fluent/discussions)

---

## 📄 License

This project is licensed under the **MIT** license. See the [LICENSE](LICENSE) file for details.

You can use it in private and commercial projects. Keep in mind that you must include a copy of the license in your project.
Binary file modified build/nuget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net10.0;net8.0;net472;net481</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageTags>assertions;fluentassertions;awesome;awesomeassertions;testing;xunit;nunit;playwright;http;client</PackageTags>
</PropertyGroup>

<ItemGroup Condition="'$(GeneratePackageOnBuild)' == 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ namespace Fluent.Client.AwesomeAssertions;
public class HttpResponseMessageTaskAssertions(Task<HttpResponseMessage> instance, AssertionChain chain)
: ReferenceTypeAssertions<Task<HttpResponseMessage>, HttpResponseMessageTaskAssertions>(instance, chain)
{
private AssertionChain chain = chain;
private readonly AssertionChain chain = chain;

protected override string Identifier => "http-response";

// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
public static JsonSerializerOptions DefaultJsonOptions = new()
{
PropertyNameCaseInsensitive = true,
Expand Down Expand Up @@ -128,7 +130,23 @@ params object[] becauseArgs

using (AssertionScope assertionScope = new())
{
TBody? body = JsonSerializer.Deserialize<TBody>(rawResponse, DefaultJsonOptions);
TBody? body;

try
{
body = JsonSerializer.Deserialize<TBody>(rawResponse, DefaultJsonOptions);
}
catch (Exception e)
{
CurrentAssertionChain
.WithDefaultIdentifier(Identifier)
.WithExpectation(
$"Expected HTTP response content to be deserializable to \"{typeof(TBody).Name}\", but deserialization threw an exception:",
assertionChain => assertionChain.FailWith(e.ToString())
);

return;
}

assertion(body!);
failuresFromInspector = assertionScope.Discard();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static class HttpResponseMessageTaskExtensions
extension(Task<System.Net.Http.HttpResponseMessage> response)
{
/// <summary>
/// Returns assertions for <see cref="HttpResponseMessage"/>.
/// Returns assertions for <see cref="global::System.Net.Http.HttpResponseMessage"/>.
/// </summary>
public HttpResponseMessageTaskAssertions Should() => new(response, AssertionChain.GetOrCreate());
}
Expand Down
Loading