Skip to content

Latest commit

 

History

History
210 lines (154 loc) · 8.1 KB

File metadata and controls

210 lines (154 loc) · 8.1 KB

GitHub Gists — Interoperability Project

A Spring Boot application that manages GitHub Gists while demonstrating multiple integration styles in one system: REST, GraphQL, SOAP, and gRPC. Built as part of the Interoperability of information systems (IIS) course at Algebra Bernays University.

The same domain (gists, authentication, weather lookup) is exposed through different protocols so clients can compare how each style handles data exchange, contracts, validation, and security.


What this project demonstrates

Area Implementation
REST CRUD on /api/gists with application/json and application/xml
GraphQL Queries and mutations at /graphql, GraphiQL at /graphiql
SOAP SearchGists endpoint at /ws, JAXB models from XSD
gRPC WeatherService.GetForecast on port 9090, consumed via REST gateway
GitHub API Optional live integration with api.github.com using a per-user PAT
Auth JWT access tokens + HttpOnly refresh cookies, role-based access
Validation JSON Schema (gist-schema.json) and XSD (gist.xsd) before persistence
Web UI Thymeleaf client at /app/gists exercising all protocols from the browser

Architecture overview

Browser (Thymeleaf + JS)
        │
        ├── REST  ──────────────► GistController ──► GistService ──► H2 / GitHub API
        ├── GraphQL ────────────► GistGraphqlController ──► GistService
        ├── SOAP search ────────► GistSearchEndpoint ──► XmlFileService
        └── Weather (REST) ─────► WeatherRestController ──► gRPC stub ──► WeatherGrpcService
                                                                              │
                                                                              ▼
                                                                    DHMZ XML feed (vrijeme.hr)

When app.use-public-api is true and the signed-in user has saved a valid GitHub personal access token (PAT), gist operations call the real GitHub API. Otherwise, data is served from the local H2 database.


Tech stack

  • Java 21, Spring Boot 3.3.5
  • Spring Web, WebFlux (WebClient), Data JPA, Security, Validation, GraphQL, Thymeleaf
  • Spring WS + JAXB (XSD → Java, SOAP endpoints)
  • gRPC + Protocol Buffers (grpc-server-spring-boot-starter)
  • H2 in-memory database
  • JJWT for access/refresh tokens
  • Bucket4j for rate limiting
  • networknt JSON Schema validator

Getting started

Prerequisites

  • JDK 21
  • Maven 3.9+

Run

mvn spring-boot:run
Service URL
Web client http://localhost:8080/app/gists
Login page http://localhost:8080/app/login
REST API http://localhost:8080/api/gists
GraphQL http://localhost:8080/graphql
GraphiQL http://localhost:8080/graphiql
SOAP WSDL http://localhost:8080/ws/gists.wsdl
Weather (REST → gRPC) http://localhost:8080/api/weather/forecast?city=Zagreb
gRPC server localhost:9090
H2 console http://localhost:8080/h2-console

Seeded users

Username Password Role Permissions
admin admin123 FULL_ACCESS GET, POST, PUT, DELETE on gists
reader reader123 READ_ONLY GET only

Authentication

  1. LoginPOST /api/auth/login with { "username", "password" } returns a short-lived access token (JSON) and sets an HttpOnly refresh cookie (SameSite=Strict).
  2. RefreshPOST /api/auth/refresh rotates the refresh token using the cookie.
  3. LogoutPOST /api/auth/logout revokes refresh tokens and clears the cookie.
  4. Protected calls — send Authorization: Bearer <access_token> on REST and GraphQL requests.

GitHub PAT

Authenticated users can store a GitHub PAT via PUT /api/auth/github-pat. The token is validated against GitHub (gist scope required) and kept server-side. With app.use-public-api: true, gist CRUD then targets the live GitHub API as that user.


API highlights

REST — /api/gists

  • GET /api/gists, GET /api/gists/{id}READ_ONLY or FULL_ACCESS
  • POST, PUT, DELETEFULL_ACCESS only
  • Request bodies validated against JSON Schema or XSD depending on Content-Type

GraphQL — /graphql

query { gists { id description owner { login } files { filename } } }

mutation {
  createGist(input: {
    description: "Hello"
    isPublic: true
    owner: { login: "me" }
    files: [{ filename: "demo.txt" }]
  }) { id }
}

SOAP — /ws

SearchGistsRequest searches gists (local XML files and/or GitHub-backed data). WSDL is published at /ws/gists.wsdl.

Dynamic WSDL previewPOST /api/soap/wsdl/preview generates WSDL from a SOAP envelope or namespace/element names (useful for learning contract-first vs. envelope-driven design).

Weather — gRPC + REST gateway

  • gRPC: WeatherService.GetForecast reads Croatian DHMZ observations from https://vrijeme.hr/hrvatska_n.xml
  • REST: GET /api/weather/forecast?city=Zagreb calls the gRPC service internally

Security features

  • Stateless JWT authentication with refresh-token rotation
  • Role-based authorization (READ_ONLY / FULL_ACCESS)
  • Rate limiting on auth and API routes (Bucket4j)
  • Content Security Policy headers (relaxed for H2 console only)
  • CORS configuration via app.security.cors-allowed-origins
  • Optional HSTS (app.security.hsts-enabled)
  • Invalid GitHub PAT handling with clear client-facing errors

Configuration

Key settings in src/main/resources/application.yml:

app:
  use-public-api: true          # false = local H2 only
  jwt:
    access-expiry-ms: 900000    # 15 minutes
    refresh-expiry-ms: 604800000  # 7 days
  security:
    rate-limit-auth-per-minute: 15
    rate-limit-api-per-minute: 400

server:
  port: 8080

grpc:
  server:
    port: 9090

Replace app.jwt.secret with a real Base64-encoded 256-bit key before any production deployment.


What I learned

Through building this project I practiced:

  1. Interoperability patterns — exposing the same business logic through REST, GraphQL, SOAP, and gRPC, and understanding when each fits.
  2. Contract-driven development — XSD and JSON Schema validation, JAXB code generation, .proto definitions, and GraphQL schema design.
  3. External API integration — calling GitHub’s REST API with WebClient, handling PAT validation, timeouts, and error mapping.
  4. Security in depth — JWT access/refresh flow with HttpOnly cookies, RBAC, rate limiting, CSP, and secure cookie attributes.
  5. Hybrid architectures — REST as a gateway over gRPC; SOAP search over XML with optional GitHub-backed results.
  6. Spring ecosystem — Spring Security filter chains, @PreAuthorize, Spring GraphQL, Spring WS endpoints, and JPA persistence.
  7. Real-world XML — parsing DHMZ weather feeds and mapping them into protobuf messages for a typed gRPC API.
  8. Developer experience — a single Thymeleaf UI to exercise every protocol, plus GraphiQL and WSDL preview for exploration.

Project structure

src/main/java/hr/projekt/gists/
├── controller/     REST controllers (gists, auth, weather, SOAP WSDL preview)
├── graphql/        GraphQL resolvers and inputs
├── grpc/           gRPC weather service
├── soap/           SOAP endpoint, XML search, dynamic WSDL tools
├── github/         GitHub API client and PAT validation
├── security/       JWT, filters, token service
├── validation/     JSON Schema and XSD validators
├── service/        Gist business logic (local DB ↔ GitHub)
└── web/            Thymeleaf page controllers

src/main/resources/
├── graphql/        gist.graphqls
├── schemas/        gist.xsd, gist-schema.json, gists-service.xsd
├── templates/      login.html, gists.html
└── static/         CSS and JS for the web client