Releases: ilyankin/kotlin-rfc9457
Releases · ilyankin/kotlin-rfc9457
Release list
v0.5.0
Added
problem-details-ktor-validation— integration with Ktor'sRequestValidationplugin.requestValidation(type)maps aRequestValidationExceptionto aProblemcarrying an
errors[]array, the multi-field pattern RFC 9457 itself recommends. Entries use the RFC's own
member names,detailandpointer.invalidField/invalidFieldsattach a JSON Pointer (RFC 6901) to a failure reason from inside
validate<T> { }. A reason written any other way degrades to adetail-only entry.jsonPointer(Customer::age)andjsonPointer<Customer>("profile", "color")derive that pointer
from the body type's serial descriptor, so a renamed member stops compiling or throws instead of
pointing at something that is gone.invalidFieldalso takes a property reference directly.- A member renamed with
@SerialNamemust be named by its serial name: mapping a Kotlin property
to a serial name needskotlin-reflect, which this library does not use. decodeValidationReasonis public, for a mapping that needs anerrors[]shape
requestValidationdoes not produce.
problem-details-core—Json.encodeToProblemValue(value)encodes any@Serializablevalue
to a standaloneProblemValue, for a value that is not a whole extension member — one element of a
ProblemArray, for instance.
Docs
- The README now leads with the document the library produces, groups its feature list by task, and
picks artifacts from an "if you want to… add…" table.
v0.4.0
Added
problem-details-ktor-client-xml—problemXml()registers the same kind of
HttpResponseValidatorhook asproblem-details-ktor-client'sproblemJson(), for responses
labeledapplication/problem+xml. Its own artifact, so a client that only decodes JSON never
resolves an XML parser. Registration order does not matter, unlike the server's
ContentNegotiationpair: each hook gates on aContent-Typethe other never matches, so neither
can shadow the other. There is no lenient mode — plainapplication/xmlnever matches — and a body
labeledapplication/problem+xmlthat fails to decode propagates asSerializationException
rather than falling back to Ktor's own exception.
v0.3.0
Added
problem-details-ktor-client—problemJson()registers a KtorHttpResponseValidatorhook
that turns a recognizedapplication/problem+jsonerror response intoproblem-details-core's
existingProblemException, the same type application code throws on the server side and
problem-details-ktoranswers. JSON only, by artifact rather than by flag, so a client that never
speaks XML never resolves an XML parser; theapplication/problem+xmlhalf is planned as its own
module. RequiresexpectSuccess = trueon the client — Ktor's own default isfalse.
Fixed
problem-details-xml— a body that is not markup at all (plain text, or a lone<) escaped
ProblemXml.decodeFromString's wrapper asIllegalStateExceptioninstead of the documented
SerializationException. xmlutil reports that one case as a bareIllegalStateExceptionrather
than anXmlException, which the wrapper did not expect.
v0.2.0
problem-details-xml and problem-details-ktor-xml publish for the first time, alongside
problem-details-core and problem-details-ktor, all on the same version.
Added
problem-details-xml— the RFC 9457 Appendix Bapplication/problem+xmlcodec (ProblemXml),
byte-exact against the RFC's own example in both directions. The generic (non-JDK) xmlutil parser
is used explicitly, so external entities are never resolved. xmlutil is animplementation
dependency; no xmlutil type appears in this module's API, thrown types included.problem-details-ktor-xml—ProblemXmlConverterandproblemXml(), registering the codec
with Ktor'sContentNegotiation.problem-details-ktorstill never depends on either XML module.
RegisterproblemXml()afterproblemJson()— order decides which format an absent or wildcard
Acceptresolves to.- Every JVM jar now declares an
Automatic-Module-Namematching its root package.
Notes
- The XML writer refuses what XML cannot express rather than writing it verbatim: an extension
member name that is not an XMLNCName, or text carryingU+0000or an unpaired surrogate. A
Problemvalid for JSON may therefore be refused here — see the module README. Every refusal
surfaces asSerializationException, never an xmlutil type. - A whitespace-only member (
detail = " ") survives an XML round trip. application/problem+xmlrequests and responses are always UTF-8, regardless of what charset was
negotiated — an XML document states its own encoding in-band.
v0.1.0
Changelog
The format follows Keep a Changelog, and this project follows
Semantic Versioning.
While the version is 0.x, any release may contain breaking changes without a deprecation cycle.
That is what 0.y.z means, and it is deliberate. Any that occur are listed under Breaking changes.
[0.1.0] — 2026-08-02
First release. JSON only: problem-details-core and problem-details-ktor. The XML modules
(problem-details-xml, problem-details-ktor-xml) are written and tested but deliberately left out
of this release.
Added
problem-details-core—Problemwith the five RFC 9457 §3.1 members and arbitrary §3.2
extensions;ProblemValue(ProblemPrimitive/ProblemArray/ProblemObject/ProblemNull);
theproblem { }builder;ProblemTypefor reusable problem kinds; typed extension access via
extensions(obj),extensionsAs<T>()andextension<T>(name).problem-details-core—ProblemSerializer, attached toProblemas its own serializer, so
extension members are written as siblings of the standard ones rather than nested under an
extensionskey, no matter which converter wins the media-type match.problem-details-core—ProblemException, aProblemthat can be thrown, and
ProblemType.exception(detail, instance, cause)to raise one from a declared problem type. It
lives in core rather than in a Ktor module, so domain code can throw a problem document without
depending on a web framework.problem-details-ktor—respondProblem, which keepsstatusin sync with the real response
status and fillsinstancefrom the request path;ProblemDetailsCatalogandproblemDetails { }
overStatusPages;ProblemJsonConverterandproblemJson()overContentNegotiation;
ProblemContentTypes.problem-details-ktor—problemDetails { }answers a thrownProblemExceptionwith the
document it carries instead of a generic 500, and logs a non-nullcausethatStatusPageswould
otherwise drop silently. The entry is seeded into the catalog, somap<ProblemException>replaces
it like any other.- Both codecs bound extension nesting at
Problem.MAX_NESTING_DEPTH(64) and fail with
SerializationExceptionrather than aStackOverflowError. - API reference at https://ilyankin.github.io/kotlin-rfc9457/, and in each
-javadoc.jar,
which is what javadoc.io serves. Every module'sREADME.mddoubles as its
module description, and the main entry points carry@sampleexamples that live incommonTest,
so they are compiled and run rather than merely written.
Notes
ProblemExceptioncarries aProblemrather than being one, and is final. Use it when the
document is assembled at the throw site; to turn an existing exception type into a problem,
keep mapping it in the catalog, which leaves that exception free of any dependency on this
library.- No
@RequiresOptInmarkers: at 0.x everything is unstable by declaration, so opt-in annotations
would carve islands out of nothing. They arrive with 1.0 for whatever is not ready to freeze. - The public surface is recorded in
api/*.apiand checked on every build, and every public
declaration in it carries KDoc —reportUndocumentedplusfailOnWarningmake an undocumented one
fail the documentation build. - The root POM is published
packaging: pomwith a compile-scoped dependency on the-jvm
artifact, so Maven consumers can use the plain coordinates.