Nedo.AspNet.ApiContracts 1.1.2

dotnet add package Nedo.AspNet.ApiContracts --version 1.1.2
                    
NuGet\Install-Package Nedo.AspNet.ApiContracts -Version 1.1.2
                    
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="Nedo.AspNet.ApiContracts" Version="1.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nedo.AspNet.ApiContracts" Version="1.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Nedo.AspNet.ApiContracts" />
                    
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 Nedo.AspNet.ApiContracts --version 1.1.2
                    
#r "nuget: Nedo.AspNet.ApiContracts, 1.1.2"
                    
#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 Nedo.AspNet.ApiContracts@1.1.2
                    
#: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=Nedo.AspNet.ApiContracts&version=1.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Nedo.AspNet.ApiContracts&version=1.1.2
                    
Install as a Cake Tool

Nedo.AspNet.ApiContracts

Standardized API contracts for ASP.NET applications. Provides consistent request/response envelopes, standard HTTP headers, Swagger integration, and built-in request validation via Nedo.AspNet.Request.Validation.

Installation

dotnet add package Nedo.AspNet.ApiContracts

Setup

using Nedo.AspNet.ApiContracts.Extensions;
using Nedo.AspNet.ApiContracts.Swagger;

var builder = WebApplication.CreateBuilder(args);

// Register ApiContracts + Request Validation
builder.Services.AddApiContracts();

builder.Services.AddControllers(options =>
{
    // Let all validation flow through Nedo.AspNet.Request.Validation
    options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
});

builder.Services.AddSwaggerGen(options =>
{
    options.OperationFilter<StandardHeaderFilter>();
    options.AddStandardAuthorization();
});

All contract classes (FilterItem, OffsetPagination, SortItem, etc.) include built-in validation attributes. Custom DTOs can also use attributes from Nedo.AspNet.Request.Validation.


1. Standard HTTP Headers

Headers are passed via HTTP headers, not in the request body. Use StandardHeaders constants for consistency.

Authorize Button (Swagger)

Header Description Example
Authorization Bearer JWT token Bearer eyJhbGciOi...
X-Role-Code Role identifier admin, user

Operation Parameters (per-endpoint)

Header Description Default
Accept-Language Language (BCP 47) id-ID
X-Timezone Timezone (IANA) Asia/Jakarta
X-Tenant-Id Tenant identifier
X-Client-Id App identifier
X-Client-Version App version
X-Correlation-Id Cross-service tracing
X-Request-Id Request tracing
X-Idempotency-Key Safe retry key

Swagger Setup

builder.Services.AddSwaggerGen(options =>
{
    options.OperationFilter<StandardHeaderFilter>();  // Per-endpoint headers
    options.AddStandardAuthorization();               // Authorize button
});

See docs/01-standard-headers.md for full details.


2. Query / Get

Request: GetRequest<TFilter> wraps a QueryRequest with pagination and sort.

{
  "data": {
    "filters": [
      { "field": "category", "operator": "Eq", "value": "Electronics" }
    ],
    "search": "macbook",
    "sort": [{ "field": "price", "direction": "Desc" }],
    "pagination": { "page": 1, "page_size": 20 }
  },
  "options": { "show_error": true }
}

Response: BaseResponse<List<T>> with QueryResponseInfo and PaginationInfo:

{
  "success": true,
  "status_code": 200,
  "code": "SUC-RTV-001",
  "message": "Products retrieved",
  "info": {
    "transaction_id": "a1b2c3d4-...",
    "timestamp": "2026-02-11T12:00:00Z",
    "operation_type": "Query",
    "correlation_id": "req-abc-123",
    "language": "id-ID",
    "timezone": "Asia/Jakarta",
    "total_ms": 125.5,
    "query_ms": 45.2,
    "count_ms": 12.3,
    "record_count": 2,
    "has_next_page": true
  },
  "data": [{ "id": 1, "name": "MacBook Pro" }, { "id": 2, "name": "iPhone 16" }],
  "pagination": {
    "page": 1,
    "page_size": 2,
    "total_count": 10,
    "total_pages": 5,
    "has_next_page": true
  },
  "error": null
}

Advanced Query Features

Feature Class Purpose
Filtering FilterItem, FilterGroup Field-level and nested AND/OR filters
Sub-query SubQueryFilter IN (SELECT ...) filters
Select SelectClause Column selection, functions, expressions
Functions SqlFunction, FunctionOperand CONCAT, UPPER, ROUND, CASE WHEN
Joins JoinClause Inner/Left/Right/Cross joins
Includes IncludeClause EF Core eager loading
Sorting SortItem Field + direction (Asc/Desc)
Pagination OffsetPagination, CursorPagination Page-based or keyset pagination
GroupBy GroupByClause, AggregateItem Grouping with Count/Sum/Avg/Min/Max
Batch BatchQueryRequest Multiple named queries in one request

Filter operators: Eq, Neq, Gt, Gte, Lt, Lte, Contains, StartsWith, EndsWith, In, NotIn, Between, NotBetween, IsNull, IsNotNull, InSubQuery, etc.


3. Insert

Request: InsertRequest<TData>

{
  "data": {
    "name": "iPad Pro",
    "price": 1099.99,
    "category": "Electronics"
  },
  "options": { "rollback_on_failure": true }
}

Response: BaseResponse<T> with InsertResponseInfo:

{
  "success": true,
  "status_code": 201,
  "code": "SUC-INS-001",
  "message": "Product created",
  "info": {
    "transaction_id": "...",
    "operation_type": "Insert",
    "total_ms": 85.3,
    "record_id": "42",
    "insert_ms": 42.1
  },
  "data": { "id": 42, "name": "iPad Pro" },
  "pagination": null,
  "error": null
}

4. Update

Request: UpdateRequest<TData> — includes id field.

{
  "id": "42",
  "data": {
    "name": "iPad Pro M4",
    "price": 1299.99
  }
}

Response: BaseResponse<T> with UpdateResponseInfo:

{
  "success": true,
  "status_code": 200,
  "code": "SUC-UPD-001",
  "message": "Product updated",
  "info": {
    "operation_type": "Update",
    "total_ms": 60.2,
    "record_id": "42",
    "update_ms": 35.8,
    "fields_changed": true
  },
  "data": { "id": 42, "name": "iPad Pro M4" },
  "error": null
}

5. Upsert

Request: UpsertRequest<TData> — insert or update.

{
  "data": {
    "id": 42,
    "name": "iPad Pro M4",
    "price": 1299.99
  }
}

Response: BaseResponse<T> with UpsertResponseInfo:

{
  "success": true,
  "status_code": 200,
  "code": "SUC-UPS-002",
  "message": "Product upserted",
  "info": {
    "operation_type": "Upsert",
    "total_ms": 55.0,
    "record_id": "42",
    "upsert_ms": 30.5,
    "was_inserted": false
  },
  "data": { "id": 42, "name": "iPad Pro M4" },
  "error": null
}

6. Delete

Request: DeleteRequest<TData> — supports soft delete.

{
  "data": 42,
  "soft_delete": true
}

Response: BaseResponse<T> with DeleteResponseInfo:

{
  "success": true,
  "status_code": 200,
  "code": "SUC-DEL-002",
  "message": "Product deleted",
  "info": {
    "operation_type": "Delete",
    "total_ms": 40.1,
    "record_id": "42",
    "delete_ms": 18.5,
    "soft_delete": true
  },
  "data": null,
  "error": null
}

7. Batch

Request: BatchRequest<TData> — multiple operations in one request.

{
  "data": [
    { "operation": "Insert", "data": { "name": "Apple Watch", "price": 399.99 } },
    { "operation": "Update", "id": "42", "data": { "name": "iPad Pro M5" } },
    { "operation": "Delete", "id": "99" }
  ],
  "options": { "rollback_on_failure": true }
}

Response: BatchResponse<T> with BatchResponseInfo:

{
  "success": true,
  "status_code": 200,
  "code": "SUC-BAT-001",
  "message": "Batch completed",
  "info": {
    "operation_type": "Batch",
    "total_ms": 210.5,
    "total_items": 3,
    "success_count": 3,
    "failure_count": 0,
    "batch_ms": 180.2,
    "transactional": true
  },
  "data": null,
  "error": null
}

Supported operations: Insert, Update, Upsert, Delete.


8. Error Handling

All errors follow a consistent structure:

{
  "success": false,
  "status_code": 400,
  "code": "VAL-001",
  "message": "Validation failed",
  "info": null,
  "data": null,
  "error": [
    {
      "data": { "name": "", "price": -10 },
      "error_details": {
        "form_errors": [
          {
            "code": "ERR-BIZ-001",
            "message": "At least one field is required",
            "fields": ["name", "price"]
          }
        ],
        "field_errors": [
          {
            "field": "name",
            "items": [
              { "code": "VAL-001", "message": "Name is required" }
            ]
          },
          {
            "field": "price",
            "items": [
              { "code": "VAL-GEN-001", "message": "Price must be positive" }
            ]
          }
        ]
      }
    }
  ]
}
Class Purpose
ErrorEntry<TData> Wraps original input + error details
ErrorDetails Contains form_errors and field_errors
FormError Form-level error with code, message, and related fields
FieldError Field path + list of error items (supports dot-notation: filters[2].value)
FieldErrorItem Individual error with code and message

Factory Methods

// Success
var response = BaseResponse<Product>.Ok(product, "Created");

// Paginated query
var response = BaseResponse<Product>.Paged(products, page: 1, pageSize: 10, totalCount: 100);

// Simple error
var response = BaseResponse<Product>.Fail("Not found", 404, "ERR-NOT-FOUND");

// Detailed validation error
var response = BaseResponse<Product>.Fail(errorEntries, 400, "VAL-001", "Validation failed");

9. ResponseInfo Reference

All response info classes inherit from BaseResponseInfo:

BaseResponseInfo (common fields)

Field Description
transaction_id Unique transaction ID
timestamp ISO 8601 timestamp
operation_type Insert, Update, Delete, Query, etc.
executed_by User who executed
module_name Service/module name
correlation_id Echoed from header
request_id Echoed from header
language Echoed from header
timezone Echoed from header
tenant_id Echoed from header
client_id Echoed from header
client_version Echoed from header
total_ms Total processing time

Pagination

Field Description
page Current page (1-based)
page_size Items per page
total_count Total items across all pages
total_pages Total pages
has_next_page Whether more pages exist

pagination is null for non-paginated responses (Insert, Update, Delete, etc.).

Operation-Specific Info Fields

Class Description Extra Fields
QueryResponseInfo Query/Get list operations query_ms, count_ms, record_count, has_next_page
GetResponseInfo Single record retrieval record_id, query_ms
InsertResponseInfo Insert operations record_id, insert_ms
UpdateResponseInfo Update operations record_id, update_ms, fields_changed
DeleteResponseInfo Delete operations record_id, delete_ms, soft_delete
UpsertResponseInfo Upsert operations record_id, upsert_ms, was_inserted
BatchResponseInfo Batch operations total_items, success_count, failure_count, batch_ms, transactional

10. Response Codes

Use ResponseCodes constants class. Format: {STATUS}-{OPERATION}-{SEQUENCE}

Success Codes

Constant Code Description
RetrievalSuccess SUC-RTV-001 Data retrieved successfully
RetrievalEmpty SUC-RTV-002 No records found
InsertSuccess SUC-INS-001 Record created
UpdateSuccess SUC-UPD-001 Record updated
UpdateNoChange SUC-UPD-002 No fields changed
DeleteSuccess SUC-DEL-001 Record hard-deleted
SoftDeleteSuccess SUC-DEL-002 Record soft-deleted
UpsertInserted SUC-UPS-001 Upsert → inserted
UpsertUpdated SUC-UPS-002 Upsert → updated
BatchSuccess SUC-BAT-001 All items succeeded
BatchPartial SUC-BAT-002 Partial success

Error Codes (App-Level)

Constant Code Description
BusinessRuleViolation ERR-BIZ-001 Business rule violated
DuplicateEntry ERR-BIZ-002 Duplicate data
StateConflict ERR-BIZ-003 State conflict
NotFound ERR-NF-001 Resource not found
RecordNotFound ERR-NF-002 Record not found
Unauthorized ERR-AUTH-001 Not authenticated
Forbidden ERR-AUTH-002 Not authorized
TokenExpired ERR-AUTH-003 Token expired
InternalError ERR-SRV-001 Server error
ServiceUnavailable ERR-SRV-002 Service unavailable
Timeout ERR-SRV-003 Request timeout

Validation Codes

Validation error codes (VAL-*) are provided by Nedo.AspNet.Request.Validation and are not in this library.

Category Code Range Examples
Generic VAL-GEN-001VAL-GEN-006 Required, MaxLength, MinLength
String VAL-STR-001VAL-STR-017 CamelCase, Alpha, NoWhitespace
Numeric VAL-NUM-001VAL-NUM-011 MinValue, Range, PositiveNumber
Date/Time VAL-DAT-001VAL-DTM-014 DateRange, PastDate, Weekday
File VAL-FIL-001VAL-FIL-006 FileType, MaxFileSize
Image VAL-IMA-001VAL-IMA-012 ImageType, MaxResolution
IP Address VAL-IPA-001VAL-IPA-026 IPv4, PrivateIP, CIDR
Phone VAL-PHN-001VAL-PHN-003 PhoneFormat, CountryCode
Money VAL-MON-001VAL-MON-007 CurrencyFormat, MinAmount
URL VAL-URL-001VAL-URL-009 ValidUrl, SecureUrl

Project Structure

src/Nedo.AspNet.ApiContracts/
├── Headers/
│   └── StandardHeaders.cs
├── Swagger/
│   ├── StandardHeaderFilter.cs
│   └── SwaggerExtensions.cs
├── Requests/
│   ├── BaseRequest.cs
│   ├── RequestOptions.cs
│   ├── GetRequest.cs
│   ├── InsertRequest.cs
│   ├── UpdateRequest.cs
│   ├── UpsertRequest.cs
│   ├── DeleteRequest.cs
│   └── BatchRequest.cs
├── Responses/
│   ├── BaseResponse.cs
│   ├── PaginationInfo.cs
│   ├── ResponseCodes.cs
│   ├── BatchResponse.cs
│   ├── Info/
│   │   ├── BaseResponseInfo.cs
│   │   ├── QueryResponseInfo.cs
│   │   ├── GetResponseInfo.cs
│   │   ├── InsertResponseInfo.cs
│   │   ├── UpdateResponseInfo.cs
│   │   ├── DeleteResponseInfo.cs
│   │   ├── UpsertResponseInfo.cs
│   │   └── BatchResponseInfo.cs
│   └── Errors/
│       ├── ErrorEntry.cs
│       ├── ErrorDetails.cs
│       ├── FormError.cs
│       ├── FieldError.cs
│       └── FieldErrorItem.cs
└── Queries/
    ├── QueryRequest.cs
    ├── QueryProfile.cs
    ├── BatchQueryRequest.cs
    ├── Filters/
    │   ├── FilterItem.cs
    │   ├── FilterGroup.cs
    │   └── SubQueryFilter.cs
    ├── Selects/
    │   ├── SelectClause.cs
    │   ├── SqlFunction.cs
    │   ├── FunctionOperand.cs
    │   ├── InlineExpression.cs
    │   └── IncludeClause.cs
    ├── Clauses/
    │   ├── SortItem.cs
    │   ├── JoinClause.cs
    │   ├── GroupByClause.cs
    │   └── AggregateItem.cs
    └── Pagination/
        ├── OffsetPagination.cs
        └── CursorPagination.cs

## Versioning & Release

This project uses **git tags** to control versioning. The GitLab CI/CD pipeline automatically builds and publishes NuGet packages when a tag is pushed.

### How It Works

1. The pipeline triggers **only on tags** (e.g. `v1.0.0`)
2. The `v` prefix is stripped to get the version number (`1.0.0`)
3. The package is built, packed, and published to **NuGet.org**

### How to Release a New Version

```bash
# 1. Commit and push your changes
git add .
git commit -m "feat: your changes"
git push origin main

# 2. Create a version tag
git tag -a v1.0.0 -m "Release v1.0.0

Added:
- Initial release of Nedo.AspNet.ApiContracts
- Standardized request/response envelopes
- Swagger integration with standard headers

Notes:
No breaking changes."


# 3. Push the tag (this triggers the CI/CD pipeline)
git push origin v1.0.0

Version Format

Type Example Tag NuGet Version
Patch v1.0.1 1.0.1
Minor v1.1.0 1.1.0
Major v2.0.0 2.0.0
Prerelease v1.1.0-beta.1 1.1.0-beta.1

The tag must start with v (e.g. v1.0.0, not 1.0.0).


Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/YourFeature)
  3. Commit your changes (git commit -m "Add awesome feature")
  4. Push to your branch (git push origin feature/YourFeature)
  5. Open a pull request

Please ensure:

  • All tests pass (dotnet test)
  • Code follows project conventions
  • Add unit tests for new features

License

MIT

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.1.2 83 2/13/2026
1.1.1 86 2/13/2026
1.1.0 83 2/12/2026
1.0.0 84 2/11/2026