A full-stack web application for retrieving weather forecasts and managing user favorite locations. The backend is built with Java Spring Boot, providing RESTful APIs to fetch geolocation and weather data from external services, as well as user management features. The frontend is a modern single-page application (SPA) built with Vite, TypeScript, and styled using Tailwind CSS.
Live Demo: frontend-howwastheweather.onrender.com
- Geocoding: Convert addresses to latitude/longitude coordinates using the Google Maps Geocoding API.
- Weather Forecasts: Retrieve current, hourly, and daily weather forecasts (up to 16 days) from the Open-Meteo API, including temperature, precipitation, wind, UV index, and more.
- User Management: Register and authenticate users with securely encoded passwords using JWT.
- Favorite Locations: Save, retrieve, and delete favorite locations for authenticated users.
- Responsive UI: A clean, modern frontend interface styled with Tailwind CSS.
- Containerized: Fully Dockerized for easy deployment and consistent environment.
- Cloud Deployment: Deployed on Render for reliable cloud hosting.
- Java 17+ with Spring Boot (JDK 23 for Docker deployment)
- Spring WebFlux: For reactive, non-blocking HTTP requests
- WebClient: For API calls to external services (Google Maps API, Open-Meteo API)
- Spring Data R2DBC: Reactive database access for user and favorite location persistence
- Spring Security: JWT-based authentication and password encoding
- PostgreSQL: Database for storing users and favorite locations
- JUnit 5 & Mockito: For unit testing
- Maven: Dependency management and build tool
- Docker: Containerization
- Vite: Fast build tool and development server
- TypeScript: Static typing for JavaScript
- Tailwind CSS: Utility-first CSS framework for responsive design
- Node.js 20: JavaScript runtime
- React: JavaScript library for building user interfaces
- Nginx: Web server for production deployment
- Docker: Containerization
-
POST /api/login
Authenticate a user and return a JWT token.
Request Body:{ "email": "string", "password": "string" }
Response:200 OKwith{ "token": "jwt-token" }or401 Unauthorizedif credentials are invalid. -
POST /api/signup
Register a new user and return a JWT token.
Request Body:{ "email": "string", "password": "string" }
Response:201 Createdwith{ "token": "jwt-token" }or400 Bad Requestif email is already in use.
-
POST /api/favorites
Add a new favorite location for the authenticated user.
Request Body:{ "name": "string", "latitude": number, "longitude": number }
Headers:Authorization: Bearer <jwt-token>
Response:200 OKwith the savedFavoriteLocationor401 Unauthorizedif not authenticated. -
GET /api/favorites
Retrieve all favorite locations for the authenticated user.
Headers:Authorization: Bearer <jwt-token>
Response:200 OKwith an array ofFavoriteLocationobjects. -
DELETE /api/favorites/{id}
Delete a favorite location by ID.
Path Parameter:id(Long)
Headers:Authorization: Bearer <jwt-token>
Response:204 No Contenton success,404 Not Foundif the ID doesn't exist.
-
GET /api/forecast/hello
Test endpoint to verify the forecast API is running.
Response:200 OKwith"Hello, world!". -
GET /api/forecast/current
Get current weather for a location.
Query Parameter:location(string, e.g., "New York")
Response:200 OKwith aCurrentWeatherDTOobject or404 Not Foundif the location is invalid. -
GET /api/forecast/hourly
Get hourly weather forecast for a location.
Query Parameter:location(string)
Response:200 OKwith aHourlyForecastDTOobject or404 Not Foundif the location is invalid. -
GET /api/forecast/daily
Get daily weather forecast for a location.
Query Parameter:location(string)
Response:200 OKwith aDailyForecastDTOobject or404 Not Foundif the location is invalid. -
GET /api/forecast/getforecast
Get the full weather forecast (current, hourly, daily) for a location.
Query Parameter:location(string)
Response:200 OKwith aForecastDTOobject or404 Not Foundif the location is invalid.
- Java 17+: For local backend development (JDK 23 for Docker deployment)
- Node.js 18+: For frontend development (Node 20 for Docker deployment)
- Maven: For backend dependency management
- PostgreSQL: Database for storing users and favorite locations
- Docker & Docker Compose (optional): For containerized setup
- API Keys:
- Google Maps API key (for geocoding)
- No key required for Open-Meteo (free tier used)
Main dependencies managed through Maven (pom.xml):
- Spring Boot Starter WebFlux
- Spring Boot Starter Security
- Spring Boot Starter Data R2DBC
- Spring Boot Starter Validation
- PostgreSQL Driver
- R2DBC PostgreSQL
- Java JWT (jjwt)
- Project Lombok
- Spring Boot Starter Test (for testing)
- Reactor Test (for reactive testing)
Main dependencies managed through npm (package.json):
- React & React DOM
- React Router DOM
- Axios (for API requests)
- Tailwind CSS
- TypeScript
- Vite
- ESLint & Prettier (for code formatting)
- Install PostgreSQL if not already installed.
- Create a database for the app:
CREATE DATABASE weather_app;
- Ensure your PostgreSQL user has the necessary permissions.
- Clone the repository:
git clone https://github.com/wesleygeorge/ForecastWebApp.git cd forecastwebbapp - Configure environment variables in
src/main/resources/application.properties:google.maps.api.key=<your-google-maps-api-key> spring.r2dbc.url=r2dbc:postgresql://localhost:5432/weather_app spring.r2dbc.username=<your-postgres-username> spring.r2dbc.password=<your-postgres-password> spring.sql.init.mode=always
- Build and run the backend:
./mvnw clean install ./mvnw spring-boot:run
- Navigate to the frontend directory:
cd ../frontend - Install dependencies:
npm install
- Run the development server:
The app will be available at
npm run dev
http://localhost:5173(or another port if configured).
-
Clone the repository:
git clone https://github.com/wesleygeorge/ForecastWebApp.git cd forecastwebapp -
Create a
.envfile in the root directory with your environment variables:GOOGLE_MAPS_API_KEY=<your-google-maps-api-key> POSTGRES_USER=<db-username> POSTGRES_PASSWORD=<db-password> POSTGRES_DB=weather_app -
Start the application using Docker Compose:
docker-compose up -d
This will start:
- PostgreSQL database
- Spring Boot backend
- React frontend with Nginx
-
Access the application at
http://localhost:80(or the configured port)
The application is deployed on Render:
- Frontend URL: frontend-howwastheweather.onrender.com
- Backend URL: howwastheweather.onrender.com
-
Create a new Web Service on Render for the backend:
- Connect your GitHub repository
- Set the build command to use Docker
- Configure environment variables (Google Maps API key, database URL, etc.)
-
Create a new Web Service on Render for the frontend:
- Connect your GitHub repository
- Set the build command to use Docker
- Configure the backend API URL as an environment variable
-
Create a PostgreSQL database on Render or use an external database service
FROM eclipse-temurin:23-jdk
WORKDIR /app
COPY . .
# Ensure mvnw is executable
RUN chmod +x ./mvnw
# If using Maven
RUN ./mvnw package -DskipTests
EXPOSE 8080
# Replace with your actual JAR file name
CMD ["java", "-jar", "target/HowWasTheWeather-0.0.1-SNAPSHOT.jar"]# Build stage
FROM node:20 AS builder
# Set working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the frontend code
COPY . .
# Build the app
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]version: "3.8"
services:
database:
image: postgres:14
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
backend:
build: ./backend
environment:
- SPRING_R2DBC_URL=r2dbc:postgresql://database:5432/${POSTGRES_DB}
- SPRING_R2DBC_USERNAME=${POSTGRES_USER}
- SPRING_R2DBC_PASSWORD=${POSTGRES_PASSWORD}
- GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}
depends_on:
- database
ports:
- "8080:8080"
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
volumes:
postgres_data:- Register or log in.
- Enter an address to get its coordinates and view current weather and hourly or daily forecasts.
- Save favorite locations.
- View and manage your saved locations from the UI.
- Backend tests are located in
backend/src/test. Run them with:./mvnw test
Feel free to submit issues or pull requests. Ensure all tests pass and follow the existing code style.
MIT


