Overview
This repository extends Carter in two places that tend to drift apart in minimal API projects: endpoint metadata and response negotiation. The core package adds response metadata helpers and a negotiator base, while the companion packages turn that base into concrete JSON, YAML, and XML negotiators that can be registered directly with Carter.
The result is a small family of packages that lets you keep route declarations explicit, keep serializer choice deliberate, and keep format-specific negotiation logic out of individual handlers. You can adopt only the core abstractions, or layer in one of the concrete negotiators when an API contract calls for a specific wire format.
Concepts
The packages in this repository are easiest to reason about when you separate the shared negotiation model from the format-specific negotiators that sit on top of it.
Keeping endpoint contracts next to route mappings
Codebelt.Extensions.Carter adds Produces<TResponse> and Produces(int) to IEndpointConventionBuilder, which keeps response metadata attached to the same route-builder code that defines the endpoint. That matters when a Carter module should stay concise while still advertising clear response contracts to tooling and downstream consumers.
This is the smallest layer in the family. If your goal is only to make route mappings describe their response shapes more explicitly, the core package is enough and you do not need one of the format-specific negotiators.
Separating negotiation flow from serializer choice
The core package also introduces ConfigurableResponseNegotiator<TOptions>, the abstraction that handles media-type matching, charset selection, and formatter-driven response writing. The concrete negotiator packages reuse that same lifecycle instead of re-implementing Carter negotiation per serializer, so the main extension point lives in one place even though the final wire formats differ.
That shared model is what makes Codebelt.Extensions.Carter.AspNetCore.Text.Json, Codebelt.Extensions.Carter.AspNetCore.Newtonsoft.Json, Codebelt.Extensions.Carter.AspNetCore.Text.Yaml, and Codebelt.Extensions.Carter.AspNetCore.Xml feel consistent. Each package swaps in its own formatter options and formatter implementation, but the negotiation boundary stays stable.
Choosing the wire format deliberately
Two packages cover JSON, but they make different trade-offs. Codebelt.Extensions.Carter.AspNetCore.Text.Json keeps the stack aligned with System.Text.Json, while Codebelt.Extensions.Carter.AspNetCore.Newtonsoft.Json exists for applications that need Newtonsoft.Json-specific configuration or compatibility.
The other two packages widen Carter's response surface beyond JSON. Codebelt.Extensions.Carter.AspNetCore.Text.Yaml is for APIs that must negotiate YAML, and Codebelt.Extensions.Carter.AspNetCore.Xml is for XML contracts that need explicit serializer and encoding control. They follow the same negotiation model as the JSON packages, but they matter only when those formats are part of the external API contract.
Usage guidance
Start with Codebelt.Extensions.Carter when you need route-level response metadata or when you want to build a custom negotiator on top of the shared negotiation base. Add exactly one concrete negotiator package for the format your handlers are expected to negotiate, and choose Codebelt.Extensions.Carter.AspNetCore.Text.Json unless you have a clear Newtonsoft.Json requirement or a non-JSON contract.
Avoid carrying a concrete format package just because it is available. If an API does not negotiate YAML or XML, Codebelt.Extensions.Carter.AspNetCore.Text.Yaml and Codebelt.Extensions.Carter.AspNetCore.Xml only add format-specific dependencies, and if you do not need serializer-specific behavior, the core package or the simpler JSON negotiator is the better boundary.