Spring Boot service for the Branch platform take-home exercise. It exposes GET /users/{username}, retrieves public GitHub user and repository data, and returns the merged JSON shape requested in docs/Platform_Coding_Exercise.txt.
- Run locally with
./mvnw spring-boot:run, or build a container withdocker build -t github-profile-api .. - Test with
./mvnw verify; the build runs the automated suite and enforces 100% line and branch coverage for reported packages. - Implementation is a single Java 21 / Spring Boot service with controller, service, client, domain, and config layers.
- GitHub calls are live at runtime, while tests use stubbed GitHub responses for repeatability.
- Successful lookups are cached briefly with Caffeine; repository pagination uses
per_page=100with a configurable max page cap. - No service-level auth is implemented because the assignment uses public GitHub data; optional
X-GitHub-Tokenpassthrough can improve GitHub rate limits and public field availability.
- Java 21
- Maven Wrapper is included; no separate Maven install is required for
./mvnwcommands - Network access to
api.github.comfor live manual calls
./mvnw spring-boot:runThe service starts on port 8080.
Build and run the service in a container:
docker build -t github-profile-api .
docker run --rm -p 8080:8080 github-profile-apiThen call the API from the host:
curl -i http://localhost:8080/users/octocatRuntime settings can be overridden with Spring Boot environment variables, for example:
docker run --rm -p 8080:8080 \
-e GITHUB_API_TIMEOUT=2s \
-e GITHUB_CACHE_TTL=10m \
github-profile-apiThe public API contract is documented in docs/openapi.yml. The Spec Kit design copy is kept at specs/001-github-profile-api/contracts/openapi.yaml.
curl -i http://localhost:8080/users/octocatExample response shape:
{
"user_name": "octocat",
"display_name": "The Octocat",
"avatar": "https://avatars.githubusercontent.com/u/583231?v=4",
"geo_location": "San Francisco",
"email": null,
"url": "https://api.github.com/users/octocat",
"created_at": "Tue, 25 Jan 2011 18:44:36 GMT",
"repos": [
{
"name": "boysenberry-repo-1",
"url": "https://api.github.com/repos/octocat/boysenberry-repo-1"
}
]
}Optional GitHub token passthrough:
curl -i -H "X-GitHub-Token: $GITHUB_TOKEN" http://localhost:8080/users/octocatThe token is forwarded to GitHub as Authorization: Bearer ... for that request only. It is not service-level authentication and is not logged or stored. Authenticated GitHub requests can improve rate limits and may allow GitHub to return public profile fields such as email when available.
Validation example:
curl -i http://localhost:8080/users/-Expected status: 400 with code INVALID_USERNAME.
Missing user example:
curl -i http://localhost:8080/users/this-user-should-not-exist-branch-demoExpected status: 404 with code PROFILE_NOT_FOUND.
./mvnw clean compile
./mvnw test
./mvnw verifyThe automated suite uses stubbed GitHub HTTP responses, so tests do not depend on live GitHub availability or rate limits.
Coverage is generated by JaCoCo during verify, and the build enforces 100% line and branch coverage for each reported package:
./mvnw verifyOpen target/site/jacoco/index.html for the HTML report, or inspect target/site/jacoco/jacoco.csv for a machine-readable summary. Spring Boot bootstrap code and the defensive SHA-256-unavailable cache-key branch are excluded from the coverage gate.
The service is intentionally a single Spring Boot application because the assignment asks for one endpoint and fast evaluator setup. The code is still separated into enterprise-style layers:
controller: HTTP contract and sanitized error responsesservice: validation, orchestration, mapping, and cache useclient: GitHub HTTP integration and upstream error translationdomain: client-facing immutable response recordsconfig: outbound HTTP and cache configuration
The controller delegates to the service. The service validates usernames, checks the cache, calls the GitHub client for user and repository data, maps the result, and caches successful lookups. The GitHub client owns external URL paths, repository pagination, response parsing, timeout handling, and upstream status translation.
No service-level authentication or authorization layer is implemented. The assignment requires access to public GitHub data and does not require clients to authenticate to this service.
Clients may optionally send X-GitHub-Token with a GitHub token. The service forwards that value only to GitHub as a bearer token for the current lookup. This is upstream GitHub authentication passthrough, not authentication to this service. Tokens are not logged, stored, or included in error responses.
Client-facing failures use stable error codes:
INVALID_USERNAMEPROFILE_NOT_FOUNDUPSTREAM_RATE_LIMITEDUPSTREAM_TIMEOUTUPSTREAM_UNAVAILABLEINTERNAL_ERROR
Error responses are intentionally sanitized. They do not expose stack traces, Java class names, secrets, or raw upstream response bodies.
Successful profile summaries are cached in memory for a short period using Caffeine. This reduces repeated GitHub calls during an evaluation session and helps avoid avoidable rate-limit pressure. Failed lookups are not cached in the initial implementation.
Cache entries are partitioned by authentication context. Unauthenticated lookups use a public username cache key. Requests with X-GitHub-Token use a SHA-256 fingerprint of the token plus the username, so authenticated and unauthenticated responses do not share cache entries and raw tokens are never stored in cache keys.
Configuration defaults live in src/main/resources/application.yml:
github.api.base-urlgithub.api.timeoutgithub.api.max-repository-pagesgithub.cache.ttl
Phase 1, functional baseline:
- Maven/Spring project setup
- GitHub user and repository retrieval
- Required response mapping
- Success-path endpoint and tests
Phase 2, reliability and defensive behavior:
- Username validation
- Not-found, rate-limit, timeout, and upstream failure handling
- Sanitized error contract tests
Phase 3, enterprise readiness:
- Short-lived caching
- Health endpoint exposure
- README and quickstart documentation
- Full compile, test, and verify checks
- No database is included because durable persistence is not required for the exercise.
- Live GitHub calls are used at runtime, but tests use HTTP stubs for repeatability.
- Repository retrieval follows GitHub pagination with
per_page=100and a configurable maximum page count to avoid unbounded upstream calls during unauthenticated evaluation. Very large GitHub accounts may therefore return a bounded subset of repositories unlessgithub.api.max-repository-pagesis increased.