Spring Boot backend for the Park Day Diary Expo app (disneyapp-frontend). It proxies and caches two free public APIs so all clients share the same upstream calls:
| Endpoint | Upstream | Purpose |
|---|---|---|
GET /api/wait-times/{park} |
queue-times.com | Live ride wait times. {park} is disneyland or california-adventure. |
GET /api/weather |
open-meteo.com | Current weather for Anaheim, CA. |
GET /actuator/health |
— | Liveness check. |
The frontend used to call queue-times and open-meteo directly from the device. Moving those calls server-side gives us:
- Shared cache. One server-side fetch serves every app instance — fewer upstream calls, faster responses, polite to free APIs.
- Decoupling. If queue-times changes its schema or we swap weather providers, only the backend changes — no app store release needed.
- A place to grow. Trip storage, push notifications when a favorite ride drops below 15 min, recommendations — all need a backend.
- Java 21
- Spring Boot 3.5
- Spring Web (REST) + RestClient (outbound HTTP)
- Spring Cache abstraction backed by Caffeine (in-memory, per-cache TTL)
- Spring Boot Actuator (health check)
This service is a thin, caching proxy in front of two generous free APIs. Both ask for credit, which this project gives in the frontend UI and below:
- Wait times — Powered by Queue-Times.com. Used per their Real Time API terms: access is free, attribution is required.
- Weather — Powered by Open-Meteo.com, licensed under CC-BY 4.0.
Please respect both providers' rate limits if you fork this — the Caffeine caches and the 5-minute notification poll interval are sized to be polite, not just fast.
src/main/java/com/disneyapp/backend/
├── DisneyAppBackendApplication.java # entry point, @EnableCaching
├── config/
│ ├── CacheConfig.java # two Caffeine caches with TTLs
│ ├── HttpClientConfig.java # one RestClient bean per upstream
│ ├── WebConfig.java # CORS for the Expo web build
│ └── GlobalExceptionHandler.java # uniform JSON error responses
├── waittimes/
│ ├── WaitTimesController.java # GET /api/wait-times/{park}
│ ├── WaitTimesService.java # fetch + map + @Cacheable
│ ├── ParkId.java # enum: DISNEYLAND, CALIFORNIA_ADVENTURE
│ └── dto/ # LiveRide, LiveLand, WaitTimesResponse, QueueTimesRaw
└── weather/
├── WeatherController.java # GET /api/weather
├── WeatherService.java
└── dto/ # CurrentWeather, OpenMeteoRaw
src/main/resources/application.yml # port, TTLs, CORS origins, base URLs
-
Java 21. On macOS:
brew install openjdk@21 sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk \ /Library/Java/JavaVirtualMachines/openjdk-21.jdk
Verify with
java -version.
You don't need Maven installed — the project ships with ./mvnw, which
downloads the right Maven version on first run.
./mvnw spring-boot:runThe server binds to http://localhost:8080. Try:
curl http://localhost:8080/api/weather | jq
curl http://localhost:8080/api/wait-times/disneyland | jq
curl http://localhost:8080/api/wait-times/california-adventure | jq
curl http://localhost:8080/actuator/healthThe first call to each endpoint hits the upstream API; subsequent calls within
the TTL are served instantly from the Caffeine cache. Watch the logs — you'll
see Cache miss — fetching ... only when the cache expires.
Everything tunable lives in src/main/resources/application.yml:
server:
port: 8080
cache:
wait-times-ttl-seconds: 60 # queue-times updates every ~5 min anyway
weather-ttl-seconds: 300 # weather changes slowly
cors:
allowed-origins:
- http://localhost:8081 # Expo Metro web
- http://localhost:19006 # legacy Expo web
- http://localhost:3000You can override any property at runtime with an env var, e.g.
SERVER_PORT=9000 ./mvnw spring-boot:run.
The Expo app reads its backend base URL from expo.extra.apiBaseUrl in
disneyAppFrontend/my-app/app.json (defaults to http://localhost:8080).
- iOS Simulator:
localhostworks as-is. - Android Emulator: handled automatically —
lib/api.tsrewriteslocalhostto10.0.2.2(the emulator's alias for the host machine). - Physical device: set
EXPO_PUBLIC_API_BASE_URL=http://<your-mac-lan-ip>:8080before runningexpo start, and make sure the device is on the same Wi-Fi.
./mvnw clean package
java -jar target/backend-0.0.1-SNAPSHOT.jarThe resulting jar is fully self-contained (embedded Tomcat included) and can be deployed to any host with a JDK 21+ runtime, or built into a container.