This project implements a federated GraphQL architecture using Spring Boot, GraphQL, PostgreSQL, and React. It consists of multiple subgraphs (university, students, teachers, classes, and grades) orchestrated by Apollo Rover for supergraph composition and Apollo Router for serving the federated API. The frontend is a React-based dashboard which also has Jest as it's testing framework, and all services are containerized using Docker Compose.
The application models a university management system with the following components:
- University Subgraph: Manages university and campus data, including queries and mutations for creating and searching universities.
- Students Subgraph: Handles student data, including grades, with queries, mutations, and subscriptions for real-time updates.
- Teachers Subgraph: Manages teacher data and their associated classes, with custom directives for data transformation and logging.
- Classes Subgraph: Manages class-related data, linked to teachers.
- Grades Subgraph: Manages student grades and GPA calculations.
- Frontend (Student Dashboard): A React-based UI running at
localhost:3000for interacting with the federated API along with Jest as it's testing framework. - PostgreSQL: Stores university and related data.
- Apollo Router: Serves the federated GraphQL API at
localhost:4000/graphql. - Apollo Rover: Composes the supergraph schema from individual subgraph schemas.
The following ASCII diagram illustrates the high-level flow of the project setup and runtime process:
+-----------------------------------+
| Host Machine |
| |
| +-------------------+ |
| | Build Subgraphs | |
| | - University JAR | |
| | - Students JAR | |
| | - Teachers JAR | |
| | - Classes JAR | |
| | - Grades JAR | |
| +-------------------+ |
| | |
| v |
| +-------------------+ |
| | Configure Files | |
| | - supergraph.yaml | |
| | - router.yaml | |
| | - schema.graphqls | |
| +-------------------+ |
| | |
| v |
| +-------------------+ |
| | docker-compose up | |
| +-------------------+ |
| | |
+------------|----------------------+
v
+-----------------------------------+
| Docker Environment |
| |
| +-------------------+ |
| | University Service| <--+--------| HTTP (8080/graphql)
| | (Subgraph) | | |
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Students Service | <--+--------| HTTP (8081/graphql)
| | (Subgraph) | | |
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Teachers Service | <--+--------| HTTP (8082/graphql)
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Classes Service | <--+--------| HTTP (8085/graphql)
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Grades Service | <--+--------| HTTP (8084/graphql)
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Postgres (DB) | <--+--------| Port 5432
| +-------------------+ | |
| | |
| +-------------------+ | |
| | Student Dashboard | <--+--------| HTTP (3000)
| | (React) | | |
| +-------------------+ | |
| | |
| +---------------------+ | |
| | Rover Service | | |
| | - Composes supergraph.graphql | |
| +---------------------+ | |
| | | |
| v | |
| +-------------------+ | |
| | Router Service | <--+--------| HTTP (4000/graphql)
| | - Serves Queries | |
| +-------------------+ |
| |
+-----------------------------------+
^
|
+------------|----------------------+
| Host Machine |
| |
| +-------------------+ |
| | Query Supergraph | |
| | (curl or client) | |
| +-------------------+ |
| |
+-----------------------------------+
The production architecture leverages AWS services and Apollo GraphOS for schema management and delivery:
+------------------------------------+
| Clients (Web/Mobile Apps, Tools) |
| |
| +-----------------------+ |
| | GraphQL Queries | |
| | (e.g., curl, Postman) | |
| +-----------------------+ |
| | |
| v |
+------------|-----------------------+
v
+---------------------------------------------------+
| Edge Layer (AWS API Gateway) |
| - HTTPS: api.example.com |
| - Rate Limiting, WAF |
| - Cognito Auth / API Keys |
| - Routes to Router ALB |
+------------|--------------------------------------+
v
+----------------------------------------+
| API Layer (Apollo Router) |
| - EKS Pods (2-10 replicas, HPA) |
| - Polls GraphOS for supergraph.graphql |
| - Routes queries to subgraphs |
| - Telemetry: Prometheus/Grafana |
| - Health: /health (8088) |
+------------|---------------------------+
| |
v v
+------------------------------------|-----------------------+
| Subgraphs Layer (EKS Pods) | |
| +-------------------+ | |
| | University Service| <--- ALB (8080/graphql) |
| | - Spring Boot JAR | |
| +-------------------+ |
| +-------------------+ |
| | Students Service | <--- ALB (8081/graphql) |
| | - Spring Boot JAR | |
| +-------------------+ |
| +-------------------+ |
| | Teachers Service | <--- ALB (8082/graphql) |
| | - Spring Boot JAR | |
| +-------------------+ |
| +-------------------+ |
| | Classes Service | <--- ALB (8085/graphql) |
| | - Spring Boot JAR | |
| +-------------------+ |
| +-------------------+ |
| | Grades Service | <--- ALB (8084/graphql) |
| | - Spring Boot JAR | |
| +-------------------+ |
| | |
+------------------------------------|-----------------------+
| | | | |
v v v v v
+------------------------------------|-----------------------+
| Data Layer | |
| - RDS PostgreSQL (Multi-AZ) for | |
| university/students/teachers | |
| - ElastiCache (Redis) for caching | |
+------------------------------------|-----------------------+
| | | | |
+------------|-----------------------|-----------------------+
| Operations Layer | |
| - CI/CD: GitHub Actions | |
| - On schema change: | |
| - Publish schemas to GraphOS | |
| - Monitoring: Prometheus, Grafana | |
| - Logging: OpenSearch (ELK) | |
| - Tracing: AWS X-Ray / Jaeger | |
| - Secrets: AWS Secrets Manager | |
| - IaC: Terraform / CDK | |
+------------------------------------|-----------------------+
^ |
| |
+-------------------------------+
| Apollo GraphOS |
| - Schema Registry |
| - Composes supergraph.graphql |
| - Delivers to Router |
+-------------------------------+
- Host Machine (Build & Configure):
- Build Spring Boot JARs for
university,students,teachers,classes, andgradessubgraphs. - Configure
supergraph.yaml,router.yaml, and schema files. - Run
docker-compose upto start all services.
- Build Spring Boot JARs for
- Docker Environment:
- Subgraphs: Each service (
university,students,teachers,classes,grades) exposes a GraphQL endpoint. - Postgres: Stores data for the
universityservice. - Student Dashboard: React frontend for querying and displaying data.
- Rover: Fetches schemas from subgraphs and composes
supergraph.graphql. - Router: Loads the supergraph and serves the federated API at
localhost:4000/graphql.
- Subgraphs: Each service (
- Host Machine (Query):
- Query the federated API at
http://localhost:4000/graphqlor interact via the React dashboard atlocalhost:3000.
- Query the federated API at
git clone https://github.com/ankitrajput0096/federated_graphql_app
cd federated_graphql_appBuild all backend services using Gradle:
./gradlew clean build
./gradlew bootJarStart all services using Docker Compose:
docker-compose up --build- Rover waits 30 seconds for subgraphs to start, then composes
supergraph.graphql. - Router waits 90 seconds, installs itself, and serves the federated API on
port 4000. - Student Dashboard runs on
port 3000with queries, mutations, and subscriptions demoed.
Example GraphQL query to fetch university and student data:
curl -X POST http://localhost:4000/graphql -H "Content-Type: application/json" -d '{"query": "query { university(id: \"1\") { id name description student { id text starRating grade { gpa } } } }"}'The React-based Student Dashboard (for students-subgraph graphql service) is available at http://localhost:3000. It demonstrates queries, mutations, and subscriptions for interacting with the federated API.
docker-compose downextend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@tag"])
type Query {
university(id: ID!): University
universities: [University!]!
searchUniversities(input: UniversityInput!): [SearchResult!]!
}
type University @key(fields: "id") {
id: ID!
name: String!
description: String
status: Status!
createdAt: Date!
ranking: Int
}
enum Status {
ACTIVE
INACTIVE
}
scalar Date
interface Entity @metadata(tag: "core") {
id: ID!
name(filter: String): String!
}
union SearchResult = University | Campus
type Campus implements Entity @key(fields: "id") {
id: ID!
name(filter: String): String!
}
input UniversityInput {
name: String!
status: Status
}
directive @metadata(tag: String!) on OBJECT | INTERFACE | FIELD_DEFINITION
type Mutation {
createUniversity(name: String!, description: String, status: Status!, ranking: Int!): University!
createCampus(id: ID!, name: String!): Campus!
}scalar GPA
directive @metadata(tag: String) on INTERFACE
interface Rateable @metadata(tag: "ratable") {
rating(filter: Int): Int
}
type Grade implements Rateable {
studentId: String!
grade: String!
gpa: GPA!
rating(filter: Int): Int
}
type Student {
id: ID!
text: String
starRating: Int!
grade: Grade!
status: GradeLevel!
}
type Query {
student(universityId: ID!): [Student!]!
allStudents: [Student!]!
}
type Mutation {
addStudent(input: StudentInput!): Student!
updateStudent(input: StudentInput!): Student!
}
type Subscription {
studentUpdated(studentId: ID!): Student!
}
type University @key(fields: "id") @extends {
id: ID! @external
student: [Student!]!
}
enum GradeLevel {
A
B
C
}
input StudentInput {
id: ID!
text: String
starRating: Int!
universityId: ID!
status: GradeLevel!
grade: GradeInput
}
input GradeInput {
studentId: String!
grade: String!
gpa: GPA!
}type University @key(fields: "id") @extends {
id: ID! @external
teacher: [Teacher!]!
}
type Teacher {
id: ID!
text: String @transform(format: "uppercase")
starRating: Int!
classes: [Class!]!
level: TeacherLevel!
details(filter: String): String @log(level: "INFO")
}
type Class implements Teachable {
id: ID!
subject: String! @transform(format: "capitalize")
teacherId: String!
duration: Time!
details(filter: String): String
}
scalar Time
enum TeacherLevel {
JUNIOR
SENIOR
}
interface Teachable @metadata(tag: "teachable") {
details(filter: String): String
}
directive @transform(format: String!) on FIELD_DEFINITION
directive @log(level: String = "INFO") on FIELD_DEFINITION | QUERY
directive @metadata(tag: String!) on INTERFACE | OBJECT
type Query {
teacher(universityId: ID!): [Teacher!]!
allTeachers: [Teacher!]!
}



