Skip to content
Back to skills

Nano Remove Custom Endpoint

ASecurity

Remove a custom, non-CRUD HTTP endpoint - two genuinely different shapes depending on the controller. A Public API endpoint's removal is just the controller action, its DTOs, and possibly a now-unused Api Client injection. An internal-service endpoint's removal is the controller action plus the paired Api Client custom request/method that called it, removed together since they're one contract. Use when the user asks to remove, delete, or drop a one-off custom action/endpoint from a Nano API o...

  • 5 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 4, 2026
content-marketinggoexpressapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 4, 2026

npx -y skills add Nano-Core/Nano.Templates --skill nano-remove-custom-endpoint --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nano Remove Custom Endpoint?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Nano Remove Custom Endpoint
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nano-core-nano-remove-custom-endpoint/badge)](https://www.skillsdirectory.com/skills/nano-core-nano-remove-custom-endpoint)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: nano-remove-custom-endpoint
description: Remove a custom, non-CRUD HTTP endpoint - two genuinely different shapes depending on the controller. A Public API endpoint's removal is just the controller action, its DTOs, and possibly a now-unused Api Client injection. An internal-service endpoint's removal is the controller action plus the paired Api Client custom request/method that called it, removed together since they're one contract. Use when the user asks to remove, delete, or drop a one-off custom action/endpoint from a Nano API or Web application.
---

# Nano remove custom endpoint

Removes a single custom HTTP action generated by `nano-add-custom-endpoint`. Read that skill
first; this one undoes exactly what it adds, following the same Public-API/internal-service split
and the same "Public API," not "gateway," terminology (see that skill's terminology note).

## Before removing anything, determine

1. **Which action, on which controller?** Confirm the exact method name and controller — "remove
   the endpoint" alone isn't enough if the controller has several custom actions.
2. **Public API or internal-service controller?** Same distinction the scaffold skill makes —
   check step 2 below for which path applies before doing anything else.
3. **Endpoint shape / naming** — confirm you have the actual file locations (which project each
   piece lives in) rather than assuming the default convention was followed.
4. **Is this actually a redundant custom endpoint, not just an unused one?** Four distinct kinds
   of "redundant," each worth naming explicitly rather than just deleting:
   - The response is now expressible via generic `.Entity` + `[Include]` — see **Converting to
     generic + Include** below instead of removing it outright.
   - A sibling custom endpoint already returns everything this one does (e.g. a single-item lookup
     that duplicates a list endpoint's already-populated shape — see
     `nano-add-custom-endpoint`'s "check whether a sibling list endpoint already makes it
     redundant" note). This is a plain removal, not a migration, but say plainly in the summary
     which sibling endpoint now covers the removed one's job, so callers know where to go instead.
   - The custom action's whole job was "the generic write plus an invariant" — see **Converting to
     a generic-action override** below instead of removing it outright.
   - Its Response DTO is now a near-duplicate of a sibling DTO because something it existed to
     route around (an indirection layer, a since-removed entity) went away — see
     `nano-add-custom-endpoint`'s "check for an existing sibling DTO" note. Removing the action and
     switching remaining callers to the sibling DTO is a plain removal too, worth naming the same
     way.
5. **Is a step in this endpoint's logic redundant because of DB-level cascade, not because the
   endpoint itself is unneeded?** Before removing or "simplifying" a composed delete/update flow,
   check whether an explicit child delete/cleanup call is actually doing something a required EF
   Core relationship's default `Cascade` behavior already does for free (see
   `nano-add-custom-endpoint`'s cascade note in step 1) — if so, that specific call is what's
   redundant, not necessarily the endpoint around it. Confirm the parent isn't soft-deletable
   (`IEntitySoftDeletable`) first — cascade doesn't apply to a soft delete, since it's an `UPDATE`,
   not a real `DELETE`.

---

## Public API path

1. **Is the injected Api Client still needed by another action on this controller?** Check every
   other action before deciding whether to also drop the constructor parameter/field — don't
   remove a dependency other actions still use, and don't leave an unused-parameter compiler
   error (`CS9113` under this solution's `TreatWarningsAsErrors`) behind either.
2. **Are the Request/Response DTOs used anywhere else?** Check for other actions in the same
   project referencing the same `<Name>Request`/`<Name>Response` classes before deleting them.

### Files/code to remove

- The controller action itself (method, its `[Http*]`/`[Route]`/`[ProducesResponseType]`
  attributes, its doc comment).
- `Requests/<Feature>/<Name>Request.cs` and `Responses/<Feature>/<Name>Response.cs` — only if
  nothing else uses them.
- If this was the controller's only custom action and it has no generic CRUD/entity backing (a
  bare `BaseController` created solely for this one endpoint), ask the user whether the now-empty
  controller should go too — an empty controller isn't broken, just dead weight, so this is a
  judgment call, not a mandatory cleanup step.

### Api Client injection

If nothing else on this controller uses the injected Api Client, remove the constructor
parameter/field. Don't remove the client's own definition or its `App:Apis` config entry as part
of this — that's `nano-remove-api-client-configuration`'s job (this app's consumption) or
`nano-remove-api-client`'s (the owning service's definition), separate decisions the user
should make explicitly rather than have cascade from removing one endpoint.

---

## Internal service path

This action **is** one half of a contract another application may call — its removal has to
account for the *paired* Api Client custom request/method the same way `nano-add-custom-endpoint`
scaffolds them together, not just the controller side.

1. **Is this action's route what another application's Api Client request targets?** This is the
   real risk here: removing it breaks that caller. This skill has no visibility into other repos'
   consumers — say so plainly rather than implying nothing calls it.
2. **Was a route constant shared** between this controller's `[Route(...)]` and the paired Api
   Client request's action attribute (per the scaffold skill's route-constant-sharing step)?
   Removing that constant is the sharpest version of the risk above — a guaranteed compile break
   for the request class that referenced it, not just a stale endpoint. Confirm before removing.
3. **Is the shared body model used anywhere else?** Since the scaffold skill defines one model
   class used by both the controller's `[FromBody]` parameter and the Api Client request's
   `[Body]` property, check nothing else references it before deleting it.

### Files/code to remove

- The controller action itself.
- The paired Api Client method on this app's own client class (`{ThisApp}.Models/Api/{ClientName}.cs`).
- The Api Client request class (`{ThisApp}.Models/Api/Requests/{Name}Request.cs`).
- The shared body model and any dedicated response POCO — only if step 3 found nothing else uses
  them.
- The route constant in `{Name}.Models/Consts/` — only if step 2 found it existed solely for this
  action.

Remove all of these together, in the same change — this mirrors how they were scaffolded
together; leaving the Api Client method in place while deleting the controller action produces a
client that compiles but 404s the moment anyone calls it, which is worse than removing neither.

If the user's actual request was narrower — "just remove the Api Client method, keep the
controller action" or vice versa — that's a real but unusual ask; confirm that's really what they
want before doing a partial removal, since it deliberately leaves one side of the contract
without the other.

---

## Converting to generic + Include (instead of removing outright)

Sometimes the reason to remove a custom endpoint isn't that it's unused — it's that
`nano-add-custom-endpoint`'s step 1 decision procedure (built-in before custom) now says it never
needed to be custom in the first place: the same response is expressible as the target entity plus
`[Include]`-tagged navigations at some `includeDepth`. Handle this as one combined migration, not a
removal followed by an unrelated addition:

1. **Confirm the shape actually fits.** Walk through `nano-add-custom-endpoint`'s step 1 limits —
   no selective `$expand`, and `[Include]` being global rather than per-caller — before assuming
   this conversion applies. If either limit bites, this endpoint should stay custom; don't force
   the conversion just because the response happens to include some navigations.
2. **Tagging `[Include]` on the entity changes its existing generic surface, not just this one
   caller's response.** Every other consumer of that entity's generic endpoints — other internal
   services, other Public APIs — becomes able to (and, depending on their own `includeDepth`,
   will) eager-load this navigation too, once it's tagged. Say this plainly and confirm with the
   user before tagging it, the same way `nano-remove-data-provider` confirms before deleting
   mappings other code depends on.
3. **Update the caller to use the generic `.Entity` call directly**, with the right `includeDepth`
   for what it actually needs (`0` for a bare entity, higher to reach the newly-tagged
   navigation(s)) — see `nano-add-custom-endpoint`'s "don't wrap plain generic calls" note in its
   Public API path; this replacement call should not go through a new custom Api Client method
   either.
4. **Then remove the custom endpoint's pieces** per the Public-API/Internal-service steps above,
   same as any other removal.

Report this to the user as one combined change: what got tagged `[Include]` and why, which other
consumers now gain visibility into it as a result, and what was removed because the generic call
now covers it.

---

## Converting to a generic-action override (instead of removing outright)

Sometimes a custom endpoint's whole job was never "a distinct operation" — it was "the generic
write, plus an invariant that must always hold" (validation before create/edit, a linked-entity
side-effect, a reference-count guard before a delete or a create). Per
`nano-add-custom-endpoint`'s "Overriding a generic CRUD action instead of a new endpoint," that
belongs as an override on the entity's own `BaseEntityController<...>` method(s), not a separate
route. Handle this as one combined migration:

1. **Confirm the endpoint doesn't need caller-context the override's fixed signature can't carry.**
   An override of `EditAsync(TEntity entity, CancellationToken)`/`DeleteAsync(Guid id,
   CancellationToken)` can't gain an extra parameter the removed custom action might have taken
   (e.g. a `tenantId` used for ownership scoping). If the removed endpoint did real
   caller-identity-based authorization — not just validation derivable from the entity/data itself
   — that check has to move to (or stay at) the calling Public API as its own pre-check (e.g. a
   scoped `QueryFirst` before calling the generic write), not disappear. Say this plainly rather
   than silently dropping the check.
2. **Identify every generic write variant the invariant must survive.** If callers can reach
   `CreateAsync`/`CreateAndGetAsync`/`CreateOrGetAsync`, or `EditAsync`/`EditAndGetAsync`, or
   `DeleteAsync`/`DeleteManyAsync` — override each variant that's actually reachable, not just the
   one the endpoint being removed happened to mirror. Missing a sibling variant reopens exactly the
   gap the custom endpoint existed to close. A guard derived from another entity's existence (e.g.
   "immutable once referenced") typically belongs on both the create and the delete variants, not
   just whichever one the removed endpoint originally covered.
3. **Move the logic, adjusting for the override's constraints**: throw
   `BadRequestException`/`NotFoundException` rather than returning bare `IActionResult`s for
   anything that must propagate correctly through an Api Client (see `nano-add-custom-endpoint`'s
   note on this); use `entity.Id` directly in a create override rather than the base call's result,
   since `BaseEntity`'s constructor already assigned it; reconcile any collection navigation via
   explicit repository calls, since generic Edit still won't do it for you.
4. **Then remove the custom endpoint's pieces** per the Internal service path steps above, same as
   any other removal — including the paired Api Client method/request the caller used, once callers
   are updated to hit the generic route directly instead.

Report this to the user as one combined change: which generic action(s) now carry the invariant,
which caller-context check (if any) had to move to the Public API instead, and what was removed
because the override now covers it.

---

## Postman collection

If the application already has a Postman collection (`Postman_<AppName>.json` in the application's own folder,
next to its `README.md`), remove this endpoint's request from it (or, if the endpoint was converted rather than
removed, update that request to match). Edit only that request; don't regenerate the file. If the file was
edited, remind the user to **Replace**-import it in Postman. If no collection exists, do nothing Postman-related.
## After making the change

- Show the user every file/method touched or deleted, grouped by concern, and which path was
  taken.
- **Public API path**: if the Api Client injection was left in place because another action still
  needs it, say so rather than leaving it unexplained.
- **Internal service path**: restate the cross-application risk from step 1 — this skill can only
  confirm nothing *local* still calls it, not that nothing anywhere does. If step 2 found a
  shared route constant, restate explicitly that removing it is a guaranteed break for whatever
  other application's request referenced it, if any.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…