ninjadog 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package ninjadog --version 1.0.0
                    
NuGet\Install-Package ninjadog -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ninjadog" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ninjadog" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ninjadog" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ninjadog --version 1.0.0
                    
#r "nuget: ninjadog, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ninjadog@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ninjadog&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ninjadog&version=1.0.0
                    
Install as a Cake Tool

<p align="center"> <img src="logo.png" alt="Ninjadog logo" width="256" /> </p>

Ninjadog

One attribute. Full REST API. Zero boilerplate.

Atypical-Consulting - ninjadog .NET 10 stars - ninjadog forks - ninjadog

License GitHub tag issues - ninjadog GitHub pull requests GitHub last commit


Quick Start

dotnet new web -n MyApi && cd MyApi
dotnet add package Ninjadog
[Ninjadog]
public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
dotnet build && dotnet run

That's it. You now have a full CRUD API with endpoints, DTOs, validation, repositories, services, mappers, and OpenAPI docs.


Table of Contents

The Problem

Writing boilerplate C# code for REST APIs is repetitive and error-prone — DTOs, mappers, validators, repositories, endpoints, API clients. Developers waste hours on mechanical plumbing code that follows predictable patterns, and every layer must stay in sync whenever the domain model changes.

Why Ninjadog?

Without Ninjadog With Ninjadog
Code you write ~500+ lines per entity ~10 lines per entity
Files to maintain 20+ per entity 1 per entity
Layers in sync Manual Automatic
Runtime cost Depends on approach Zero (compile-time)
Reflection Often required None
Time to full CRUD Hours Seconds

Ninjadog uses C# Source Generators to produce your entire API stack at compile time. No runtime reflection, no code-gen CLI step, no files to keep in sync. Change your entity, rebuild, done.

What Gets Generated

For each entity annotated with [Ninjadog], the generator produces:

Category Generated Files Description
Endpoints 5 Create, GetAll (paginated), GetOne, Update, Delete
Contracts 7 DTOs, request objects, response objects
Data Layer 4 Repository + interface, service + interface
Mapping 4 Domain-to-DTO, DTO-to-Domain, Domain-to-Contract, Contract-to-Domain
Validation 2 Create + Update request validators
OpenAPI 5 Summaries for each endpoint
Database 2 Initializer + connection factory
Clients 2 C# and TypeScript API clients
Total ~30 files From a single annotated class

Generated HTTP Endpoints

POST   /products              Create a new product
GET    /products              List all products (paginated: ?page=1&pageSize=10)
GET    /products/{id:guid}    Get a single product
PUT    /products/{id:guid}    Update a product
DELETE /products/{id:guid}    Delete a product

Route constraints are dynamic — :guid, :int, or untyped — based on your entity's key type.

Generated Output Examples

All examples below are real generated code from Ninjadog's verified snapshot tests.

<details> <summary><strong>Endpoint — GetAll with pagination</strong></summary>

public partial class GetAllTodoItemsEndpoint
    : EndpointWithoutRequest<GetAllTodoItemsResponse>
{
    public ITodoItemService TodoItemService { get; private set; } = null!;

    public override void Configure()
    {
        Get("/todo-items");
        AllowAnonymous();
    }

    public override async Task HandleAsync(CancellationToken ct)
    {
        var page = int.TryParse(HttpContext.Request.Query["page"], out var p) && p > 0 ? p : 1;
        var pageSize = int.TryParse(HttpContext.Request.Query["pageSize"], out var ps) && ps > 0 ? ps : 10;

        var (todoItems, totalCount) = await TodoItemService.GetAllAsync(page, pageSize);
        var todoItemsResponse = todoItems.ToTodoItemsResponse(page, pageSize, totalCount);
        await SendOkAsync(todoItemsResponse, ct);
    }
}

</details>

<details> <summary><strong>Endpoint — GetOne with route constraint</strong></summary>

public partial class GetTodoItemEndpoint
    : Endpoint<GetTodoItemRequest, TodoItemResponse>
{
    public ITodoItemService TodoItemService { get; private set; } = null!;

    public override void Configure()
    {
        Get("/todo-items/{id:guid}");
        AllowAnonymous();
    }

    public override async Task HandleAsync(GetTodoItemRequest req, CancellationToken ct)
    {
        var todoItem = await TodoItemService.GetAsync(req.Id);

        if (todoItem is null)
        {
            await SendNotFoundAsync(ct);
            return;
        }

        var todoItemResponse = todoItem.ToTodoItemResponse();
        await SendOkAsync(todoItemResponse, ct);
    }
}

</details>

<details> <summary><strong>Validator — type-aware (skips value types)</strong></summary>

public partial class CreateTodoItemRequestValidator : Validator<CreateTodoItemRequest>
{
    public CreateTodoItemRequestValidator()
    {
        RuleFor(x => x.Title)
            .NotEmpty()
            .WithMessage("Title is required!");

        RuleFor(x => x.Description)
            .NotEmpty()
            .WithMessage("Description is required!");

        RuleFor(x => x.DueDate)
            .NotEmpty()
            .WithMessage("DueDate is required!");

        // IsCompleted (bool), Priority (int), Cost (decimal) — skipped, value types always have defaults
    }
}

</details>

<details> <summary><strong>Database — SQLite schema with type-aware columns</strong></summary>

public partial class DatabaseInitializer(IDbConnectionFactory connectionFactory)
{
    public async Task InitializeAsync()
    {
        using var connection = await connectionFactory.CreateConnectionAsync();

        await connection.ExecuteAsync(@"CREATE TABLE IF NOT EXISTS TodoItems (
            Id CHAR(36) PRIMARY KEY,
            Title TEXT NOT NULL,
            Description TEXT NOT NULL,
            IsCompleted INTEGER NOT NULL,
            DueDate TEXT NOT NULL,
            Priority INTEGER NOT NULL,
            Cost REAL NOT NULL)");
    }
}

</details>

Features

  • Full CRUD generation — Create, Read All (paginated), Read One, Update, Delete
  • API clients — C# client via /cs-client, TypeScript client via /ts-client
  • Type-aware validation — Value types (int, bool, decimal) skip .NotEmpty() rules automatically
  • Dynamic entity keys — Supports Guid, int, string keys with any property name (not hardcoded to Id)
  • Type-aware database schema — SQLite columns map correctly (INTEGER, REAL, TEXT, CHAR(36))
  • Dynamic route constraints — Routes use :guid, :int, etc. based on key type
  • Pagination?page=1&pageSize=10 with TotalCount metadata in responses
  • OpenAPI summaries — Each endpoint gets Swagger documentation
  • Database initializer — Schema creation and connection factory generation
  • CLI tooling — Project scaffolding and code generation commands
  • SaaS frontend — Blazor web application for configuration
  • Snapshot tested — 14 Verify snapshot tests cover template output correctness

Tech Stack

Layer Technology
Runtime .NET 10, C# 13
Code Generation Roslyn Source Generators
API Framework FastEndpoints
Database SQLite + Dapper
Validation FluentValidation
OpenAPI FastEndpoints.Swagger
Client Generation FastEndpoints.ClientGen
Architecture Domain-Driven Design (DDD)
SaaS Frontend Blazor
Build Cake Frosting

Getting Started

Prerequisites

Installation

Option 1 — NuGet Package (recommended)

dotnet add package Ninjadog

Option 2 — From Source

git clone https://github.com/Atypical-Consulting/ninjadog.git
cd ninjadog
dotnet build

Usage

Basic Example

  1. Create a new .NET 10 Web API project:
dotnet new web -n MyApi
cd MyApi
dotnet add package Ninjadog
  1. Define your domain entity with the [Ninjadog] attribute:
using Ninjadog;

[Ninjadog]
public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
  1. Build and run — all REST endpoints, contracts, repositories, services, mappers, and validators are generated automatically:
dotnet build
dotnet run

Your API is now live with full CRUD endpoints for Product.

Multiple Entities

Each entity gets its own isolated set of generated files:

[Ninjadog]
public class Movie
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public int Year { get; set; }
}

[Ninjadog]
public class Order
{
    public int OrderId { get; set; }    // int key — routes use :int constraint
    public string CustomerName { get; set; }
    public decimal Total { get; set; }
}

Architecture

┌───────────────────────────────────────────────┐
│              Your C# Source                    │
│         [Ninjadog] Domain Entities            │
└──────────────────┬────────────────────────────┘
                   │
                   ▼
┌───────────────────────────────────────────────┐
│            Roslyn Compiler                    │
│       Ninjadog Source Generators              │
└──────────────────┬────────────────────────────┘
                   │
     ┌─────────────┼─────────────┐
     ▼             ▼             ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│Contracts │ │   Data   │ │ Clients  │
│ Requests │ │   DTOs   │ │  C# /TS  │
│Responses │ │  Mappers │ │          │
└──────────┘ └──────────┘ └──────────┘
     │             │             │
     ▼             ▼             ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│Endpoints │ │  Repos   │ │Validators│
│  CRUD    │ │ Services │ │ OpenAPI  │
└──────────┘ └──────────┘ └──────────┘
                   │
                   ▼
┌───────────────────────────────────────────────┐
│           Compiled Assembly                   │
│      Full REST API — Zero Boilerplate         │
└───────────────────────────────────────────────┘

Project Structure

ninjadog/
├── src/
│   ├── library/                             # Core generator libraries
│   │   ├── Ninjadog.Engine/                 # Main source generator engine
│   │   ├── Ninjadog.Engine.Core/            # Core generator abstractions
│   │   ├── Ninjadog.Engine.Infrastructure/  # Infrastructure utilities
│   │   ├── Ninjadog.Helpers/                # Shared helper functions
│   │   ├── Ninjadog.Settings/               # Generator configuration
│   │   └── Ninjadog.Settings.Extensions/    # Settings extension methods
│   ├── tools/
│   │   └── Ninjadog.CLI/                    # Command-line interface
│   ├── templates/
│   │   └── Ninjadog.Templates.CrudWebApi/   # CRUD Web API template
│   ├── saas/
│   │   ├── Ninjadog.SaaS/                   # SaaS backend
│   │   ├── Ninjadog.SaaS.WebApp/            # SaaS Blazor frontend
│   │   └── Ninjadog.SaaS.ServiceDefaults/   # Service defaults
│   ├── tests/
│   │   └── Ninjadog.Tests/                  # Snapshot + unit tests
│   └── build/
│       └── Ninjadog.Build/                  # Cake Frosting build scripts
├── doc/                                     # Generator documentation
├── Ninjadog.sln                             # Solution file
└── global.json                              # .NET SDK version config

Generators

Ninjadog includes 30 generators organized into 11 categories. Each generator produces either a single shared file or a per-entity file.

Category Generators Scope
Core NinjadogGenerator Single file
Contracts — Data DtoGenerator Per entity
Contracts — Requests Create, Delete, Get, Update Per entity
Contracts — Responses GetAllResponse, Response Per entity
Database DatabaseInitializer, DbConnectionFactory Single file
Endpoints Create, Delete, GetAll, Get, Update Per entity
Mapping ApiContract-to-Domain, Domain-to-ApiContract, Domain-to-Dto, Dto-to-Domain Single file
Repositories Repository, RepositoryInterface Per entity
Services Service, ServiceInterface Per entity
Summaries Create, Delete, GetAll, Get, Update Per entity
Validation CreateRequestValidator, UpdateRequestValidator Per entity

Full documentation for each generator is available in doc/generators/.

CLI

The ninjadog CLI provides project scaffolding and management commands:

ninjadog init              # Initialize a new Ninjadog project
ninjadog build             # Build and run the generator engine
ninjadog add               # Add a new template or module
ninjadog list-templates    # List available templates
ninjadog validate          # Validate project configuration
ninjadog info              # Display project information
ninjadog clean             # Clean up the project directory
ninjadog test              # Run project tests

Roadmap

  • Solution that compiles
  • Branding — Name
  • Type-aware code generation
  • Dynamic entity key support
  • Pagination support
  • CLI build command
  • Template snapshot tests
  • CI/CD pipeline
  • Branding — Logo
  • Branding — Tagline
  • Benefits of the solution
  • Target audience definition
  • Write documentation
  • A client demo
  • NuGet package publishing

Want to contribute? Pick any roadmap item and open a PR!

Contributing

Contributions are welcome! Here's how to get started:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Run the tests to make sure everything works:
    dotnet test
    
  4. Commit using conventional commits (git commit -m 'feat: add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Development Setup

git clone https://github.com/Atypical-Consulting/ninjadog.git
cd ninjadog
dotnet build
dotnet test

Where to Look

  • Generator templatessrc/library/Ninjadog.Engine/
  • Snapshot testssrc/tests/Ninjadog.Tests/Templates/
  • CLI commandssrc/tools/Ninjadog.CLI/
  • Generator docsdoc/generators/

License

This project is licensed under the Apache License 2.0 — see the LICENSE file for details.


Built with care by Atypical Consulting — opinionated, production-grade open source.

Contributors

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 88 3/12/2026
1.2.1 88 3/11/2026
1.2.0 78 3/11/2026
1.1.1 88 3/11/2026
1.1.0 80 3/11/2026
1.0.4 84 3/11/2026
1.0.2 83 3/10/2026
1.0.1 81 3/10/2026
1.0.0 86 3/10/2026