Skip to content

Add web api skill and tests#613

Open
sayedihashimi wants to merge 5 commits into
mainfrom
dev/sayedha/add-webapi
Open

Add web api skill and tests#613
sayedihashimi wants to merge 5 commits into
mainfrom
dev/sayedha/add-webapi

Conversation

@sayedihashimi
Copy link
Copy Markdown
Member

Adds the dotnet-webapi skill to the dotnet-aspnet plugin. This skill guides the creation and modification of ASP.NET Core Web API endpoints with correct HTTP semantics, OpenAPI metadata, and error handling.

I'm running the skill validator now and I will add the results as a comment when it completes.

This PR replaces the closed PR #493

What's included

New skill: plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md

A comprehensive skill covering the following areas:

  • API style detection — Scans existing projects to determine whether to use controllers or minimal APIs; defaults to minimal APIs for new projects and never mixes styles.
  • Request/response types — Enforces sealed record DTOs with proper naming conventions (CreateXxxRequest, XxxResponse), XML doc comments, and DateTimeOffset for timestamps.
  • Minimal API endpoints — Guides use of TypedResults with explicit Results<T1, T2> return types, CancellationToken forwarding, and OpenAPI endpoint metadata (WithName, WithSummary, WithDescription).
  • Controller-based endpoints — Follows [ApiController] conventions with ActionResult<T> return types and ProducesResponseType attributes.
  • HTTP semantics — Ensures correct status codes (201 Created with Location header for POST, 204 No Content for DELETE, etc.).
  • OpenAPI/Swagger — Uses the built-in .NET 9+ AddOpenApi()/MapOpenApi() instead of Swashbuckle; includes XML doc comment integration and JsonStringEnumConverter for enum serialization.
  • Error handling — Implements IExceptionHandler with RFC 7807 ProblemDetails, exception-to-status-code mapping, and a sealed handler class in a Middleware/ folder.
  • .http test files — Generates test files for verifying endpoints directly from the IDE.

Copilot AI review requested due to automatic review settings May 5, 2026 18:24
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Skill Coverage Report

Plugin Skill Covered Coverage
dotnet-aspnet dotnet-webapi 38/43 88.4%
Uncovered: dotnet-aspnet/dotnet-webapi
  • [Validation] DELETE endpoints return 204 No Content (line 464)
  • [Validation] A .http file exists with a request for every new endpoint (line 474)
  • [Validation] dotnet build passes with zero errors and zero warnings (line 475)
  • [CodePattern] [HttpGet] (line 248)
  • [CodePattern] [Range] (line 147)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new dotnet-webapi skill under the dotnet-aspnet plugin plus corresponding eval coverage, extending the repository's ASP.NET guidance for endpoint design, OpenAPI wiring, and centralized API error handling.

Changes:

  • Added plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md with end-to-end guidance for controllers vs minimal APIs, DTOs, status codes, OpenAPI, exception handling, services, and .http files.
  • Added tests/dotnet-aspnet/dotnet-webapi/eval.yaml with three scenarios covering new minimal APIs, ProblemDetails-based exception handling, and extending existing controller-based APIs.
Show a summary per file
File Description
plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md New ASP.NET Core Web API skill content covering API style selection, DTO conventions, OpenAPI setup, error handling, and verification steps.
tests/dotnet-aspnet/dotnet-webapi/eval.yaml New eval scenarios and assertions for validating the dotnet-webapi skill behavior.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (4)

tests/dotnet-aspnet/dotnet-webapi/eval.yaml:123

  • This negative regex is also applied to the full response, so a correct controller-based answer can fail just by saying "don't use MapGet/MapPost here". Because the scenario is specifically about preserving controller style, forbidding any mention of minimal API methods makes the eval brittle and likely to reject good explanations.
      - type: "output_not_matches"
        pattern: "app\\.(MapGet|MapPost|MapPut|MapDelete|MapPatch)|\\b(MapGet|MapPost|MapPut|MapDelete|MapPatch)\\b"

plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:273

  • AddOpenApi() is not universally available "with no additional packages required". This repository already treats Microsoft.AspNetCore.OpenApi as an explicit package dependency (for example tests/dotnet-nuget/convert-to-cpm/simple-solution/Web/Web.csproj:7 and plugins/dotnet-upgrade/skills/migrate-dotnet9-to-dotnet10/SKILL.md:133). If an existing app doesn't already reference that package, following this guidance will produce uncompilable code.
**For .NET 9+ projects**, use the built-in ASP.NET Core OpenAPI support
(`builder.Services.AddOpenApi()` + `app.MapOpenApi()` in development).
This is all that is needed — no additional packages required.

plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:366

  • This sample writes ProblemDetails with WriteAsJsonAsync, which uses the normal JSON content type. That means the response is application/json instead of RFC 7807's application/problem+json, so the example does not actually implement the "all error responses use Problem Details format" contract described above.
        httpContext.Response.StatusCode = statusCode;
        await httpContext.Response.WriteAsJsonAsync(new ProblemDetails
        {
            Status = statusCode,
            Title = title,
            // Do not use exception.Message here — it may leak sensitive internal details.
            // Use a safe, user-facing message instead.
            Detail = title,
            Instance = httpContext.Request.Path
        }, cancellationToken);

plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:314

  • The wording here says to configure enum serialization "for both minimal APIs and controllers" and then shows ConfigureHttpJsonOptions and AddControllers().AddJsonOptions(...). In a minimal-API project that encourages registering MVC services unnecessarily, which conflicts with the earlier "do not mix styles" guidance. The instruction should say to apply the configuration block for the API style already in use.
**Enum serialization (strings by default):** Configure JSON serialization so
enums appear as readable strings in both API responses and OpenAPI schemas.
Always add this configuration unless the user explicitly requests integer
enum serialization. Configure it for both minimal APIs and controllers, as
they use different option types:

```csharp
// Minimal APIs
builder.Services.ConfigureHttpJsonOptions(options =>
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()));

// Controllers / MVC
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
    });
</details>


- **Files reviewed:** 2/2 changed files
- **Comments generated:** 2


Comment thread tests/dotnet-aspnet/dotnet-webapi/eval.yaml
Comment thread plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md
@sayedihashimi
Copy link
Copy Markdown
Member Author

/evaluate

github-actions Bot added a commit that referenced this pull request May 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Skill Validation Results

Skill Scenario Quality Skills Loaded Overfit Verdict
dotnet-webapi Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics 2.0/5 → 4.3/5 🟢 ✅ dotnet-webapi; tools: skill, read_bash, stop_bash / ✅ dotnet-webapi; tools: skill 🟡 0.28
dotnet-webapi Add error handling with ProblemDetails and IExceptionHandler 3.0/5 → 5.0/5 🟢 ✅ dotnet-webapi; tools: skill, view, report_intent, bash / ✅ dotnet-webapi; tools: skill, report_intent 🟡 0.28
dotnet-webapi Add a new API endpoint to an existing controller-based project 2.7/5 → 5.0/5 🟢 ✅ dotnet-webapi; tools: skill, edit, bash / ✅ dotnet-webapi; tools: skill, bash, edit 🟡 0.28

Model: claude-opus-4.6 | Judge: claude-opus-4.6

🔍 Full Results - additional metrics and failure investigation steps

▶ Sessions Visualisation -- interactive replay of all evaluation sessions

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 6, 2026 01:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (6)

plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:367

  • This IExceptionHandler example writes ProblemDetails with WriteAsJsonAsync, which produces a normal JSON response instead of the RFC 7807 application/problem+json payload that the surrounding guidance requires. It also bypasses any AddProblemDetails() customizations, so consumers following this sample won't actually get the standardized problem-details response format.
        httpContext.Response.StatusCode = statusCode;
        await httpContext.Response.WriteAsJsonAsync(new ProblemDetails
        {
            Status = statusCode,
            Title = title,
            // Do not use exception.Message here — it may leak sensitive internal details.
            // Use a safe, user-facing message instead.
            Detail = title,
            Instance = httpContext.Request.Path
        }, cancellationToken);

plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:452

  • Step 7 makes .http request files part of the skill's workflow, but none of the new eval scenarios assert on that output. This means the skill can regress on one of the PR's advertised features without any test failure.
### Step 7: Create a .http test file

After implementing endpoints, create a `.http` file in the project root that
demonstrates how to call every new endpoint. This serves as living
documentation and a quick manual test harness.

```http
@baseUrl = http://localhost:5000

### Get all products
GET {{baseUrl}}/api/products

### Get product by ID
GET {{baseUrl}}/api/products/1

### Create a product
POST {{baseUrl}}/api/products
Content-Type: application/json

{
  "name": "Wireless Mouse",
  "price": 29.99,
  "category": "Electronics"
}

### Delete a product
DELETE {{baseUrl}}/api/products/1

Include at least one request per endpoint with realistic bodies. Show error
paths (e.g., non-existent IDs). Match the port to launchSettings.json.

**tests/dotnet-aspnet/dotnet-webapi/eval.yaml:131**
* This scenario asks for only a collection GET and a POST, but the rubric requires `CreatedAtAction` on the POST. `CreatedAtAction` needs a concrete target action (normally a `GetById` route), so a model can only satisfy the rubric by inventing an extra endpoint that the prompt never requested or by generating a broken location link.
  Add a new OrdersController with a GET endpoint to list orders and a
  POST endpoint to create an order. Each order has a customer ID, a
  placedAt timestamp, a total amount, and an OrderStatus (Pending,
  Processing, Shipped, Delivered, Cancelled).
assertions:
  - type: "output_contains"
    value: "ControllerBase"
  - type: "output_contains"
    value: "[ApiController]"
  - type: "output_contains"
    value: "CancellationToken"
  - type: "output_not_matches"
    pattern: "app\\.(MapGet|MapPost|MapPut|MapDelete|MapPatch)|\\b(MapGet|MapPost|MapPut|MapDelete|MapPatch)\\b"
  - type: "output_contains"
    value: "DateTimeOffset"
  - type: "output_matches"
    pattern: "/// <summary>"
rubric:
  - "Continues with the controller pattern since the existing project uses controllers (does not mix minimal APIs)"
  - "Includes CancellationToken in all endpoint signatures"
  - "POST create returns CreatedAtAction with 201 status, not Ok with 200"
**plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:241**
* This example assumes every POST has a corresponding `GetById` action or route. For create-only/collection-only APIs, following it literally either forces the model to invent an extra endpoint or produces a `Location` link to an action that doesn't exist. The guidance should explain that `CreatedAtAction`/`CreatedAtRoute` is only valid when a retrievable resource route is actually present.

POST 201 responses: Always return a Location header pointing to the
newly created resource.

  • Controllers: use CreatedAtAction(nameof(GetById), new { id = ... }, response)
  • Minimal APIs: use TypedResults.Created($"/api/products/{id}", response)
**tests/dotnet-aspnet/dotnet-webapi/eval.yaml:123**
* This negative regex is so broad that it also rejects perfectly valid controller-based answers that merely mention minimal APIs in prose (for example, 'don't use `MapGet` here because the project already uses controllers'). That makes the scenario brittle and can fail correct responses for talking about the forbidden pattern instead of actually using it.
  - type: "output_not_matches"
    pattern: "app\\.(MapGet|MapPost|MapPut|MapDelete|MapPatch)|\\b(MapGet|MapPost|MapPut|MapDelete|MapPatch)\\b"
**plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md:416**
* Using `AddScoped` as the default example is unsafe for the in-memory storage pattern this skill promotes elsewhere. A scoped service is recreated for every request, so if the implementation keeps its in-memory collection in instance state, newly created items disappear on the next request and the sample API won't behave like a persistent store even within one process.

Register with the interface, not the concrete type:

// In Program.cs
builder.Services.AddScoped<IProductService, ProductService>();
  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment thread plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md
Comment thread tests/dotnet-aspnet/dotnet-webapi/eval.yaml
@sayedihashimi
Copy link
Copy Markdown
Member Author

/evaluate

1 similar comment
@sayedihashimi
Copy link
Copy Markdown
Member Author

/evaluate

github-actions Bot added a commit that referenced this pull request May 6, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Skill Validation Results

Skill Scenario Quality Skills Loaded Overfit Verdict
dotnet-webapi Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics 1.7/5 ⏰ → 4.3/5 🟢 ✅ dotnet-webapi; tools: skill, view, create, edit 🟡 0.29
dotnet-webapi Add error handling with ProblemDetails and IExceptionHandler 3.0/5 → 4.7/5 🟢 ✅ dotnet-webapi; tools: skill, view / ✅ dotnet-webapi; tools: skill 🟡 0.29
dotnet-webapi Add a new API endpoint to an existing controller-based project 3.0/5 → 4.7/5 🟢 ✅ dotnet-webapi; tools: skill, edit, view / ✅ dotnet-webapi; tools: skill, view 🟡 0.29

timeout — run(s) hit the (600s) scenario timeout limit; scoring may be impacted by aborting model execution before it could produce its full output (increase via timeout in eval.yaml)

Model: claude-opus-4.6 | Judge: claude-opus-4.6

🔍 Full Results - additional metrics and failure investigation steps

▶ Sessions Visualisation -- interactive replay of all evaluation sessions

@sayedihashimi
Copy link
Copy Markdown
Member Author

@BrennanConroy this PR is now in good shape. It's the same PR as before with a minor update from copilot. You should be able to approve and merge now.

cc @mikekistler

Copy link
Copy Markdown

@mikekistler mikekistler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carrying forward my approval from #565

@sayedihashimi
Copy link
Copy Markdown
Member Author

/evaluate

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Skill Validation Results

Skill Scenario Quality Skills Loaded Overfit Verdict
dotnet-webapi Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics 2.3/5 → 4.7/5 🟢 ✅ dotnet-webapi; tools: skill / ✅ dotnet-webapi; tools: skill, stop_bash 🟡 0.28
dotnet-webapi Add error handling with ProblemDetails and IExceptionHandler 2.7/5 → 5.0/5 🟢 ✅ dotnet-webapi; tools: skill / ✅ dotnet-webapi; tools: skill, view 🟡 0.28
dotnet-webapi Add a new API endpoint to an existing controller-based project 2.3/5 → 4.7/5 🟢 ✅ dotnet-webapi; tools: skill, view / ✅ dotnet-webapi; tools: skill, view, edit 🟡 0.28

Model: claude-opus-4.6 | Judge: claude-opus-4.6

🔍 Full Results - additional metrics and failure investigation steps

▶ Sessions Visualisation -- interactive replay of all evaluation sessions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants