Project Layout and Discovery
This page explains how tapik finds endpoint contracts and where generated files end up.
If generation does not behave the way you expect, this is usually the first page to check.
tapik scans compiled classes, not source files
The generation flow starts from compiled output under the module’s main classes directory.
That has two important consequences:
-
the relevant code has to compile first,
-
discovery behavior follows the compiled class layout, not just the source tree.
The Gradle plugin wires tapikGenerate to the classes task so the usual workflow stays straightforward.
Discovery starts from basePackage
The Gradle extension points tapik at one base package:
tapik {
basePackage("com.acme.catalog")
}
tapik then scans compiled classes under that package and looks for concrete types assignable to API.
If the configured base package is too narrow, endpoints outside it will not be discovered. If it is too broad, tapik will still only keep types that match the API contract.
What counts as a discoverable API
In practice, the safest pattern is:
-
concrete class or object,
-
implements
API, -
under the configured base package,
-
exposes properties or methods that produce
HttpEndpointvalues.
The delegated endpoint property form is the common case, but discovery also works from endpoint-returning members more generally.
Nested API types are discovered separately
If you have multiple API implementors under the scanned package, tapik treats them as separate discovery targets.
That is useful when you want separate generated surfaces. It also means tapik does not automatically merge nested API types into one logical contract unless your source organization already does that.
Where generated files go
The Gradle plugin uses two output locations:
-
build/generated/sources/tapik/main/kotlinfor generated Kotlin source, -
build/generatedfor non-source outputs such asAPI.mdandtapik-endpoints.txt.
Generated Kotlin sources are added to the main source set automatically.
By default, generated Kotlin types are written under a generated package segment relative to the source package.
Why this layout matters
Today this workflow is exposed through the Gradle plugin.
The shared generation engine is already separated from Gradle-specific wiring, which keeps the build integration boundary clear and avoids coupling discovery to one build tool’s task model.