Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Jalalx/HttpClientCodeGenerator

HttpClientGenerator is a tool that uses the Roslyn code generator feature to write boilerplate HttpClient code for you.
https://github.com/Jalalx/HttpClientCodeGenerator

csharp-sourcegenerator httpclient roslyn-generator source-generator

Last synced: 3 months ago
JSON representation

HttpClientGenerator is a tool that uses the Roslyn code generator feature to write boilerplate HttpClient code for you.

Awesome Lists containing this project

README

        

# HttpClientGenerator

![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/jalalx/HttpClientCodeGenerator/Main/main)
![HttpClientGenerator Nuget (with prereleases)](https://img.shields.io/nuget/vpre/httpclientgenerator)

HttpClientGenerator is a tool that uses [Roslyn source generator feature](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/) to write boilerplate HttpClient code for you.

## The Philosophy
> You should not write or generate boilerplate code. Your repository should not host or track auto-generated code.

This leaves you with:
* A much cleaner codebase
* No need for calling generator tool everytime HTTP contracts change
* You do not need to maintain or have a separate tool around out of your repo
* And no dependency on any 3rd-party code at runtime!

### Installing
```sh
dotnet add package HttpClientGenerator
```

### Usage
1. Create a console app (net5.0 app)
2. Install the `HttpClientGenerator` nuget package
3. Add following code to your project:
```csharp
//using area
using HttpClientGenerator.Shared;
using System.Text.Json.Serialization;
// ...
namespace ConsoleClientApp
{
// Make sure to mark the class and method as partial!
public partial class ToDoHttpService
{
[HttpGet("todos/{id}")]
public partial Task GetToDoItemByIdAsync(int id);
}

public class ToDoItem
{
[JsonPropertyName("id")]
public int Id { get; set; }

[JsonPropertyName("firstName")]
public int? UserId { get; set; }

[JsonPropertyName("title")]
public string Title { get; set; }

[JsonPropertyName("completed")]
public bool IsCompleted { get; set; }
}
}
```
Notice to the `partial` keyword on class and method definition. The library generates the required `GetToDoItemByIdAsync` method for you. All you need to do is to call the method like this:
```csharp
static class Program
{
static async Task Main(string[] args)
{
// Todo: Use HttpClientFactory to create HttpClient instance. Read more at:
// https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");

// The tool will generate a constructor with HttpClient argument for you
var todoService = new ToDoHttpService(client);

// Simply call the partial method, the tool has generated the required code for you
var item = await todoService.GetToDoItemByIdAsync(1);

Console.WriteLine($"Task {item.Title}: completed: {item.IsCompleted}");
}

Console.Read();
}
}
```

Behind the scene, the tool generates following code for you:
```csharp
//
// This code was generated by HttpClientCodeGenerator.
//

using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using ConsoleClientApp;
using HttpClientGenerator.Shared;

namespace ConsoleClientApp
{
public partial class ToDoHttpService
{
protected readonly HttpClient _httpClient;

public ToDoHttpService(HttpClient httpClient)
{
_httpClient = httpClient;
}

public partial async Task GetToDoItemByIdAsync(int id)
{
const string @___httpMethod = "GET";

var @___path = "todos/{id}";
var @___routes = new Dictionary();
@___routes["id"] = id;

var @___queryParams = new Dictionary();
// Query String dictionary goes here...

var @___headers = new Dictionary();
// Header dictionary goes here...

return await HttpClientGenerator.Shared.HttpClientHelper.SendAsync(_httpClient, @___httpMethod, @___path, @___headers, @___routes, @___queryParams);
}

}
}

```
NOTE: *This code is generated on the fly and is not written on disc so you don't have to worry about adding it to source control or debugging it.*

4. Now you can build and run!

```
// output
Task delectus aut autem: completed: False
```

It's cool, isn't it?

### Default JSON serializer
You can change the default `JsonSerializerOptions` by modifying the singleton reference at `HttpClientHelper.DefaultJsonSerializerOptions`. In the default implementation `JsonSerializerOptions.PropertyNameCaseInsensitive` is set to `true` to cover most use cases.

### About `HttpClient` injection

The tool automatically adds a constructor with a `HttpClient` parameter in the generated code but you can provide
a `HttpClient` instance manually by using one of the following methods:

#### Introducing a field or property

If you add a constructor and provide a `HttpClient` field or property, the generator will use that field:

```csharp
public partial class ToDoHttpService
{
// The generator will pick up this field (or Property)
protected readonly HttpClient _httpClient;

// protected HttpClient HttpClient { get; } = new HttpClient();

public ToDoHttpService(HttpClient httpClient)
{
_httpClient = httpClient;
}
// ... rest of code
}
```

#### Introducing a method

If you have a parameterless method that returns `HttpClient`, the generator will pick it up:

```csharp
public partial class ToDoHttpService
{
// The generator will call this method when needs a HttpClient instance
private HttpClient MyCustomHttpClientResolver()
{
var client = new HttpClient();
// initialize the client here...
return client;
}
// ... rest of code
}
```

### Recommended way:
We strongly suggest to use `IHttpClientFactory` to resolve `HttpClient` instances. You can read more about it here: [Use IHttpClientFactory to implement resilient HTTP requests](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests)

### Known Issues
* You will currently need to restart Visual Studio 2019 to see IntelliSense and get rid of errors with the early tooling experience.
* During development of this library using Visual Studio, make sure [you have read this issue](https://github.com/dotnet/roslyn/issues/48083).
* If you are using Visual Studio Code (Omnisharp C# extension) you might see some red lines under the partial method.
Until now, there is no full support for this feature on Omnisharp, but dotnet SDK will work without problem.

**Please feel free to open issue for reporting a bug or missing feature.**