Noundry.Connector

A powerful API connector library for .NET that provides strongly-typed HTTP clients with automatic authentication and comprehensive features.

Key Features

🚀 CLI Code Generator

Interactive wizard to generate strongly-typed C# models and Refit interfaces from REST APIs.

🔐 Automatic Authentication

Built-in authentication handling with support for various auth schemes and token management.

🎯 Type-Safe API Clients

Compile-time safety with strongly-typed models and enhanced IntelliSense support.

🔄 Full CRUD Operations

Complete support for Create, Read, Update, and Delete operations with intuitive APIs.

🔍 Advanced LINQ Support

Powerful querying capabilities with full LINQ integration for complex data operations.

⚙️ Dependency Injection Support

Seamless integration with ASP.NET Core DI container and modern .NET patterns.

Installation

Get started with Noundry.Connector in minutes

CLI Tool

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

Core Library

Add the Noundry.Connector library to your .NET project.

Package Installation:

dotnet add package Noundry.Connector

CLI Generator Workflow

The CLI tool provides an interactive wizard to generate your API clients

1

Enter API URL

Provide your REST API base URL

2

Configure Auth

Set up authentication requirements

3

Discover Endpoints

Automatically find API endpoints

4

Analyze Schemas

Parse response schemas and types

5

Generate Code

Create ready-to-use client files

CLI Commands & Options

Comprehensive guide to all CLI commands and configuration options

Basic Usage

Start the interactive wizard to generate your API client:

# Start the interactive generator
noundry-connector generate

# Or use the short form
noundry-connector gen

Command Line Options

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

Configuration File

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

Supported Authentication Types

API Key Authentication

--auth-type ApiKey

Supports header and query parameter API keys

Bearer Token

--auth-type Bearer

JWT and other bearer token schemes

OAuth 2.0

--auth-type OAuth2

Full OAuth 2.0 flow with token refresh

No Authentication

--auth-type None

For public APIs without authentication

Complete Demo Walkthrough

Follow along with this complete example using JSONPlaceholder API

1

Install the CLI Tool

# Install globally
dotnet tool install -g Noundry.Connector.Generator

# Verify installation
noundry-connector --version
2

Generate Client for JSONPlaceholder

# 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"
3

Review Generated Files

The generator creates several files:

Generated/
├── Models/
│   ├── Post.cs
│   ├── User.cs
│   ├── Comment.cs
│   └── Album.cs
├── Interfaces/
│   └── IJsonPlaceholderClient.cs
├── JsonPlaceholderClient.cs
└── ServiceCollectionExtensions.cs
4

Add Generated Files to Your Project

# 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
5

Register in Dependency Injection

// 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();
6

Use in Your Services

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);
    }
}

Advanced CLI Features

Powerful features for complex API scenarios

OpenAPI/Swagger Support

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"

Custom Templates

Use custom code generation templates:

# Use custom template directory
noundry-connector generate \
  --templates "./CustomTemplates"

# List available templates
noundry-connector templates list

Batch Processing

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"

Update Existing Clients

Regenerate when APIs change:

# Update existing client
noundry-connector update \
  --config "./noundry-connector.json"

# Compare with existing
noundry-connector diff \
  --config "./noundry-connector.json"

Troubleshooting & FAQ

Common issues and their solutions

Common Issues

SSL Certificate Issues

If you encounter SSL certificate errors:

noundry-connector generate --ignore-ssl-errors

Authentication Failures

For APIs requiring authentication during discovery:

noundry-connector generate --auth-header "Authorization: Bearer YOUR_TOKEN"

Large API Responses

For APIs with large response payloads:

noundry-connector generate --sample-size 10 --timeout 60

Proxy Configuration

Working behind a corporate proxy:

noundry-connector generate --proxy "http://proxy.company.com:8080"

Frequently Asked Questions

Q: Can I customize the generated code?

A: Yes! You can provide custom templates or use partial classes to extend the generated code without modifying the generated files directly.

Q: How do I handle API versioning?

A: Use different namespaces and client names for different versions, or configure version headers in your authentication settings.

Q: What if my API doesn't have OpenAPI documentation?

A: The CLI can discover endpoints by making sample requests and analyzing responses. It works with any REST API that returns JSON.

Q: Can I use this with existing HttpClient code?

A: Absolutely! The generated clients work alongside existing HttpClient code and can be gradually adopted.

Q: How do I contribute or report issues?

A: Visit our GitHub repository to report issues, request features, or contribute to the project.

Programmatic Library Usage

Use Noundry.Connector directly without the CLI generator

Manual Setup

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);
});

Token Authentication

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();

OAuth 2.0 Authentication

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";
});

Advanced LINQ Querying

Query API responses like in-memory collections with full LINQ support

Complex Filtering & Aggregation

// 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();

Cross-Entity Relationships

// 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();

Real-World Use Cases

Production-ready examples for common scenarios

E-Commerce Platform Integration

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();
    }
}

Social Media Analytics

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)
    };
}

Quick Usage Examples

See how easy it is to work with generated API clients

Dependency Injection Setup

builder.Services.AddJsonPlaceholderClient("https://jsonplaceholder.typicode.com");

Service Implementation

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);
    }
}

Benefits of Strongly-Typed Models

Compile-time Safety

Catch errors at compile time instead of runtime

Enhanced IntelliSense

Better code completion and documentation

Improved Refactoring

Safe code changes across your entire project

Better Performance

Optimized serialization and reduced allocations

Type Documentation

Self-documenting code with clear type definitions

Team Collaboration

Consistent APIs across development teams