Java client for the Crowdin API v2 and Crowdin Enterprise API v2, distributed via JitPack (com.github.crowdin:crowdin-api-client-java).
Two pins are load-bearing: write Java 8 code (sourceCompatibility = 8 — no var, no List.of, no streams-toList()), and leave the Gradle wrapper at 7.6.4 (the build uses Gradle-7-only Jacoco APIs; CI validates the wrapper).
src/main/java/com/crowdin/client/Client.java— entry point;@Getteron the class generates everyget<X>Api()accessorsrc/main/java/com/crowdin/client/<resource>/<Resource>Api.java+<resource>/model/— one lowercase package per resourcesrc/main/java/com/crowdin/client/core/—CrowdinApibase class, HTTP client, Jackson setup, shared modelssrc/test/java/com/crowdin/client/<resource>/<Resource>ApiTest.java— tests on theTestClientharness (framework/package)src/test/resources/api/<resource>/*.json— request/response fixtures
- Build + test (what CI runs):
./gradlew build - Tests only:
./gradlew test; one class:./gradlew test --tests "com.crowdin.client.labels.LabelsApiTest" - Coverage:
./gradlew jacocoTestReport
There is no linter or formatter — match the style of neighboring files by hand.
Fetch the endpoint spec first (see Crowdin API reference below). Then:
- Implement the method on
<Resource>Api extends CrowdinApi: build URLs fromthis.url, add query params withHttpRequestConfig.buildUrlParams(...)(overloads cap at 14 pairs), declarethrows HttpException, HttpBadRequestException, and returnResponseObject<T>/ResponseList<T>(Void.classfor empty responses). - Models are Lombok
@DataPOJOs in<resource>/model/— write no getters, setters, or equals by hand. Jackson is configured for field-only visibility and the codebase uses no@JsonProperty: field names must match the API JSON keys exactly, or values silently drop. Every list endpoint needs a<X>ResponseListwith a hand-written staticto(...)mapping toResponseList.of(...). Params classes extendingPaginationneed@EqualsAndHashCode(callSuper = true). - Enums implement
EnumConverter<T>: an instanceto(...)plus a staticfrom(String)that the deserializer finds by reflection — a missingfromfails at runtime, not compile time. Polymorphic models need a deserializer registered inJacksonJsonTransformer; fields the API returns as[]instead of an object need@JsonDeserialize(using = EmptyArrayToNullDeserializer.class). - For a new resource, register it in
Client.javawith four edits: the import (alphabetical), aprivate final <X>Api <x>Api;field, and its construction in both constructors ((Credentials)and(Credentials, ClientConfig)).@Gettergenerates the accessor. - Test by extending
TestClient(the test class is itself a client wired toTestHttpClient): implementgetMocks()returningRequestMock.build(url, method, requestFile, responseFile)entries, add fixture JSON undersrc/test/resources/api/<resource>/, and callthis.get<X>Api().... Mocks match query params exactly (pre-encode spaces as%20) and compare the serialized request body against the fixture — a new optional query param must stay absent when null or existing mocks for that URL break. - Javadoc every public method with
@param/@returnand a@seelist linking both the developer.crowdin.com and enterprise operation URLs (CI publishes Javadoc).
A complete new resource looks like the Style Guides commit: the Api class, models with response wrappers, the four Client.java edits, tests, and fixtures — no README changes.
Before implementing or changing any endpoint, fetch its spec from the llms.txt indexes (pick by environment, then project type):
- https://support.crowdin.com/_llms-txt/api/crowdin/file-based.txt — Crowdin API, file-based projects (start here)
- https://support.crowdin.com/_llms-txt/api/crowdin/string-based.txt — Crowdin API, string-based projects
- https://support.crowdin.com/_llms-txt/api/enterprise/file-based.txt — Crowdin Enterprise API, file-based projects
- https://support.crowdin.com/_llms-txt/api/enterprise/string-based.txt — Crowdin Enterprise API, string-based projects
Each index links one spec file per route (e.g. .../api.projects.strings.get.txt) with the exact request and response shapes.
- Conventional Commits for commit messages and PR titles; CI lints PR titles.
- PRs target
master. - Keep the public API backward compatible.
- Never bump the version by hand — the Release workflow rewrites
build.gradleand everyx.y.zoccurrence inREADME.md.
A change is ready when:
./gradlew buildpasses (compile + tests),- every new or changed endpoint method has a
TestClientmock test with request/response fixtures, and - every new or changed public method has Javadoc with both operation links.