A powerful API connector library for .NET that provides strongly-typed HTTP clients with automatic authentication and comprehensive features.
Interactive wizard to generate strongly-typed C# models and Refit interfaces from REST APIs.
Built-in authentication handling with support for various auth schemes and token management.
Compile-time safety with strongly-typed models and enhanced IntelliSense support.
Complete support for Create, Read, Update, and Delete operations with intuitive APIs.
Powerful querying capabilities with full LINQ integration for complex data operations.
Seamless integration with ASP.NET Core DI container and modern .NET patterns.
Get started with Noundry.Connector in minutes
Install the CLI generator tool globally or locally in your project.
Global Installation:
dotnet tool install -g Noundry.Connector.Generator
Local Installation:
dotnet new tool-manifest
dotnet tool install Noundry.Connector.Generator
Add the Noundry.Connector library to your .NET project.
Package Installation:
dotnet add package Noundry.Connector
The CLI tool provides an interactive wizard to generate your API clients
Provide your REST API base URL
Set up authentication requirements
Automatically find API endpoints
Parse response schemas and types
Create ready-to-use client files
Comprehensive guide to all CLI commands and configuration options
Start the interactive wizard to generate your API client:
# Start the interactive generator
noundry-connector generate
# Or use the short form
noundry-connector gen
Skip the interactive wizard by providing parameters directly:
# Generate with specific options
noundry-connector generate \
--url "https://api.example.com" \
--namespace "MyApp.ApiClients" \
--output "./Generated" \
--auth-type "Bearer" \
--client-name "ExampleApiClient"
# Available options:
--url, -u API base URL
--namespace, -n Generated code namespace
--output, -o Output directory (default: ./Generated)
--auth-type, -a Authentication type (None, ApiKey, Bearer, OAuth2)
--client-name, -c Generated client class name
--config-file, -f Use configuration file
--verbose, -v Enable verbose logging
--dry-run, -d Preview without generating files
--force Overwrite existing files
Create a noundry-connector.json
file for reusable configurations:
{
"apiUrl": "https://api.example.com",
"namespace": "MyApp.ApiClients",
"outputPath": "./Generated",
"clientName": "ExampleApiClient",
"authentication": {
"type": "Bearer",
"tokenEndpoint": "https://api.example.com/auth/token",
"clientId": "your-client-id",
"scopes": ["api.read", "api.write"]
},
"generation": {
"includeDocumentation": true,
"generateInterfaces": true,
"useNullableTypes": true,
"dateTimeFormat": "ISO8601"
},
"endpoints": {
"include": ["users", "posts", "comments"],
"exclude": ["internal", "debug"]
}
}
noundry-connector generate --config-file noundry-connector.json
--auth-type ApiKey
Supports header and query parameter API keys
--auth-type Bearer
JWT and other bearer token schemes
--auth-type OAuth2
Full OAuth 2.0 flow with token refresh
--auth-type None
For public APIs without authentication
Follow along with this complete example using JSONPlaceholder API
# Install globally
dotnet tool install -g Noundry.Connector.Generator
# Verify installation
noundry-connector --version
# Start the generator
noundry-connector generate
# Follow the interactive prompts:
# > API URL: https://jsonplaceholder.typicode.com
# > Client Name: JsonPlaceholderClient
# > Namespace: MyApp.ApiClients
# > Output Directory: ./Generated
# > Authentication: None (public API)
# Or use command line options:
noundry-connector generate \
--url "https://jsonplaceholder.typicode.com" \
--client-name "JsonPlaceholderClient" \
--namespace "MyApp.ApiClients" \
--output "./Generated" \
--auth-type "None"
The generator creates several files:
Generated/
├── Models/
│ ├── Post.cs
│ ├── User.cs
│ ├── Comment.cs
│ └── Album.cs
├── Interfaces/
│ └── IJsonPlaceholderClient.cs
├── JsonPlaceholderClient.cs
└── ServiceCollectionExtensions.cs
# Add the core library
dotnet add package Noundry.Connector
# Copy generated files to your project
cp -r Generated/* src/MyApp/
# Or include them directly from the Generated folder
// In Program.cs or Startup.cs
using MyApp.ApiClients;
var builder = WebApplication.CreateBuilder(args);
// Register the generated client
builder.Services.AddJsonPlaceholderClient("https://jsonplaceholder.typicode.com");
var app = builder.Build();
using MyApp.ApiClients;
using MyApp.ApiClients.Models;
public class BlogService
{
private readonly IJsonPlaceholderClient _apiClient;
public BlogService(IJsonPlaceholderClient apiClient)
{
_apiClient = apiClient;
}
public async Task<IEnumerable<Post>> GetUserPostsAsync(int userId)
{
var posts = await _apiClient.GetPostsAsync();
return posts.Where(p => p.UserId == userId);
}
public async Task<Post> CreatePostAsync(Post post)
{
return await _apiClient.CreatePostAsync(post);
}
public async Task UpdatePostAsync(int id, Post post)
{
await _apiClient.UpdatePostAsync(id, post);
}
public async Task DeletePostAsync(int id)
{
await _apiClient.DeletePostAsync(id);
}
}
Powerful features for complex API scenarios
Generate from OpenAPI specifications:
# From Swagger URL
noundry-connector generate \
--swagger-url "https://api.example.com/swagger.json"
# From local file
noundry-connector generate \
--swagger-file "./openapi.yaml"
Use custom code generation templates:
# Use custom template directory
noundry-connector generate \
--templates "./CustomTemplates"
# List available templates
noundry-connector templates list
Generate multiple clients at once:
# Use batch configuration
noundry-connector batch \
--config "./batch-config.json"
# Generate from multiple URLs
noundry-connector batch \
--urls "api1.com,api2.com,api3.com"
Regenerate when APIs change:
# Update existing client
noundry-connector update \
--config "./noundry-connector.json"
# Compare with existing
noundry-connector diff \
--config "./noundry-connector.json"
Common issues and their solutions
If you encounter SSL certificate errors:
noundry-connector generate --ignore-ssl-errors
For APIs requiring authentication during discovery:
noundry-connector generate --auth-header "Authorization: Bearer YOUR_TOKEN"
For APIs with large response payloads:
noundry-connector generate --sample-size 10 --timeout 60
Working behind a corporate proxy:
noundry-connector generate --proxy "http://proxy.company.com:8080"
A: Yes! You can provide custom templates or use partial classes to extend the generated code without modifying the generated files directly.
A: Use different namespaces and client names for different versions, or configure version headers in your authentication settings.
A: The CLI can discover endpoints by making sample requests and analyzing responses. It works with any REST API that returns JSON.
A: Absolutely! The generated clients work alongside existing HttpClient code and can be gradually adopted.
A: Visit our GitHub repository to report issues, request features, or contribute to the project.
Use Noundry.Connector directly without the CLI generator
Define your models and Refit interface manually for full control:
// 1. Define your model
public class User
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("email")]
public string Email { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
// 2. Define Refit interface
public interface IUserApi
{
[Get("/users")]
Task<IEnumerable<User>> GetUsersAsync(CancellationToken cancellationToken = default);
[Get("/users/{id}")]
Task<User> GetUserAsync(int id, CancellationToken cancellationToken = default);
[Post("/users")]
Task<User> CreateUserAsync([Body] User user);
}
// 3. Register in DI
services.AddConnector<IUserApi>(options =>
{
options.BaseUrl = "https://api.example.com";
options.Timeout = TimeSpan.FromSeconds(30);
});
Add bearer token or API key authentication:
// Bearer Token Authentication
services.AddTokenAuthentication("your-api-token");
services.AddConnector<IYourApi>(options =>
{
options.BaseUrl = "https://api.example.com";
options.DefaultHeaders["User-Agent"] = "MyApp/1.0.0";
});
// Inject and use
var api = serviceProvider.GetRequiredService<IYourApi>();
var data = await api.GetDataAsync();
Configure OAuth 2.0 with automatic token refresh:
// Configure OAuth 2.0 for GitHub API
services.AddOAuthAuthentication(config =>
{
config.ClientId = configuration["GitHub:ClientId"];
config.ClientSecret = configuration["GitHub:ClientSecret"];
config.TokenEndpoint = "https://github.com/login/oauth/access_token";
config.Scope = "repo user:email";
});
// Configure GitHub API client
services.AddConnector<IGitHubApi>(options =>
{
options.BaseUrl = "https://api.github.com";
options.DefaultHeaders["Accept"] = "application/vnd.github.v3+json";
});
Query API responses like in-memory collections with full LINQ support
// Get all orders and perform complex analysis
var orders = await orderClient.GetOrdersAsync();
// Find high-value customers
var vipCustomers = orders
.GroupBy(o => o.CustomerId)
.Select(g => new {
CustomerId = g.Key,
TotalSpent = g.Sum(o => o.TotalAmount),
OrderCount = g.Count(),
AverageOrderValue = g.Average(o => o.TotalAmount),
LastOrderDate = g.Max(o => o.CreatedAt)
})
.Where(c => c.TotalSpent > 10000 || c.OrderCount > 50)
.OrderByDescending(c => c.TotalSpent)
.ToList();
// Analyze product performance
var productStats = orders
.SelectMany(o => o.Items)
.GroupBy(item => item.ProductId)
.Select(g => new {
ProductId = g.Key,
TotalQuantitySold = g.Sum(item => item.Quantity),
TotalRevenue = g.Sum(item => item.Price * item.Quantity),
AveragePrice = g.Average(item => item.Price)
})
.OrderByDescending(ps => ps.TotalRevenue)
.ToList();
// Get data from multiple endpoints
var users = await userClient.GetUsersAsync();
var posts = await postClient.GetPostsAsync();
var comments = await commentClient.GetCommentsAsync();
// Analyze user engagement across entities
var userEngagement = users
.Select(u => new {
User = u,
PostCount = posts.Count(p => p.AuthorId == u.Id),
CommentCount = comments.Count(c => c.AuthorId == u.Id),
PostsWithComments = posts
.Where(p => p.AuthorId == u.Id)
.Count(p => comments.Any(c => c.PostId == p.Id))
})
.Where(ue => ue.PostCount > 0) // Only active users
.OrderByDescending(ue => ue.PostCount + ue.CommentCount)
.ToList();
Production-ready examples for common scenarios
Personalized recommendations and inventory management:
public class ECommerceService
{
private readonly IProductApi _productApi;
private readonly IOrderApi _orderApi;
public async Task<List<Product>> GetPersonalizedRecommendationsAsync(int customerId)
{
// Get customer order history
var orders = await _orderApi.GetCustomerOrdersAsync(customerId);
var allProducts = await _productApi.GetProductsAsync();
// Analyze purchase patterns
var purchasedProductIds = orders
.SelectMany(o => o.Items)
.Select(item => item.ProductId)
.Distinct()
.ToHashSet();
var preferredCategories = orders
.SelectMany(o => o.Items)
.Join(allProducts, item => item.ProductId, product => product.Id,
(item, product) => product.CategoryId)
.GroupBy(categoryId => categoryId)
.OrderByDescending(g => g.Count())
.Take(3)
.Select(g => g.Key)
.ToList();
// Generate recommendations
return allProducts
.Where(p => !purchasedProductIds.Contains(p.Id))
.Where(p => preferredCategories.Contains(p.CategoryId))
.OrderByDescending(p => p.Rating)
.Take(10)
.ToList();
}
}
Analyze viral content and engagement patterns:
public async Task<ViralContentReport> AnalyzeViralContentAsync(DateTime startDate, DateTime endDate)
{
var posts = await _postApi.GetPostsByDateRangeAsync(startDate, endDate);
var engagements = await _engagementApi.GetEngagementsByDateRangeAsync(startDate, endDate);
// Identify viral content
var viralPosts = posts
.Select(post => new {
Post = post,
TotalEngagements = engagements
.Where(e => e.PostId == post.Id)
.Sum(e => e.Count),
EngagementRate = engagements
.Where(e => e.PostId == post.Id)
.Sum(e => e.Count) / (double)post.ViewCount
})
.Where(p => p.TotalEngagements > 1000 && p.EngagementRate > 0.05)
.OrderByDescending(p => p.TotalEngagements)
.Take(50)
.ToList();
return new ViralContentReport
{
ViralPosts = viralPosts.Select(vp => vp.Post).ToList(),
AverageEngagementRate = viralPosts.Average(vp => vp.EngagementRate)
};
}
See how easy it is to work with generated API clients
builder.Services.AddJsonPlaceholderClient("https://jsonplaceholder.typicode.com");
public class PostService
{
private readonly JsonPlaceholderClient _client;
public PostService(JsonPlaceholderClient client)
{
_client = client;
}
public async Task<IEnumerable<Post>> GetRecentPostsAsync()
{
var posts = await _client.GetAllPostsAsync();
return posts
.Where(p => p.UserId <= 5)
.OrderByDescending(p => p.Id)
.Take(10);
}
}
Catch errors at compile time instead of runtime
Better code completion and documentation
Safe code changes across your entire project
Optimized serialization and reduced allocations
Self-documenting code with clear type definitions
Consistent APIs across development teams