Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 2–5 Years

Revise the Fresher Tier

  • Revise: Core Java Fundamentals (Fresher Tier)
  • Revise: Collections, Threads, Java 8 & Coding (Fresher Tier)
  • Revise: Spring Core, Spring Boot & Spring MVC (Fresher Tier)
  • Revise: Hibernate, SQL, Microservices, Maven & Git (Fresher Tier)

Intermediate Core Java

  • Intermediate OOP & Language Features — Interview Questions
  • Enums, Generics, Pass-by-Value & Imports — Interview Questions
  • Collections Internals & Scenarios — Interview Questions
  • JVM, Memory & Class Loading — Interview Questions
  • Exception Design & Serialization Edge Cases — Interview Questions

Java 8 Deep Dive & Stream Coding

  • Lambdas, Functional Interfaces & Method References — Interview Questions
  • Default Methods, Backward Compatibility & Optional — Interview Questions
  • Stream API Internals (Part 1) — Interview Questions
  • Stream API Internals (Part 2) — Interview Questions
  • Stream Coding Problems (Level 2, Part 1) — Interview Questions
  • Stream Coding Problems (Level 2, Part 2) — Interview Questions

Concurrency & Multithreading

  • Synchronization, Locks & Deadlocks — Interview Questions
  • Executors, ThreadLocal & Concurrent Collections — Interview Questions

Spring Framework In Depth

  • Bean Lifecycle, Contexts & Circular Dependencies — Interview Questions
  • Spring Bean Conflicts, AOP, Batch & Injection Styles — Interview Questions

Spring Boot In Depth & Scenarios

  • Spring Boot Internals & Auto-Configuration — Interview Questions
  • Spring Boot Configuration, Profiles & Secrets — Interview Questions
  • Spring Boot Data, Transactions & Caching — Interview Questions
  • Spring Boot Testing, Error Pages & Deployment — Interview Questions
  • Spring Boot Performance, Scaling & Resilience — Interview Questions
  • Spring Boot Async, Events & Messaging — Interview Questions
  • Spring Boot Security Scenarios — Interview Questions
  • Actuator, AOP, Spring Cloud & Distributed Tracing — Interview Questions
  • External APIs, Files, GraphQL & WebFlux — Interview Questions

Spring Security

  • Spring Security — OAuth2, CORS, CSRF & Access Rules — Interview Questions
  • Spring Security — Passwords, Filter Chain, Sessions & Debugging — Interview Questions

Apache Kafka

  • Kafka Architecture, Topics & ZooKeeper vs KRaft — Interview Questions
  • Kafka Producers, Consumers, Reliability & Streams — Interview Questions
  • Kafka Security, Connect & Core Scenarios — Interview Questions
  • Kafka Production Scenarios — Interview Questions

Git, Maven & Gradle (Level II)

  • Git Workflows, Rebase & Conflict Handling — Interview Questions
  • Git Recovery, Hooks, Tags & Collaboration — Interview Questions
  • Maven Builds, Multi-Module Projects & Dependency Resolution — Interview Questions
  • Maven Profiles, settings.xml, Plugins & Quality Gates — Interview Questions
  • Gradle Fundamentals, Migration & Dependencies — Interview Questions
  • Gradle Performance, Plugins, Testing & Publishing — Interview Questions

Deployment & CI/CD

  • Sessions, CI/CD Pipelines, Rollbacks & Secrets — Interview Questions
  • Migrations, Zero-Downtime Releases, Containers & Monitoring — Interview Questions

JUnit 5 & Mockito

  • JUnit 5 — Interview Questions
  • Mockito Basics — Interview Questions
  • Mockito Advanced & Tricky Questions — Interview Questions
Chaturmind
← Java Interview Prep: 2–5 Years

Revise the Fresher Tier

  • Revise: Core Java Fundamentals (Fresher Tier)
  • Revise: Collections, Threads, Java 8 & Coding (Fresher Tier)
  • Revise: Spring Core, Spring Boot & Spring MVC (Fresher Tier)
  • Revise: Hibernate, SQL, Microservices, Maven & Git (Fresher Tier)

Intermediate Core Java

  • Intermediate OOP & Language Features — Interview Questions
  • Enums, Generics, Pass-by-Value & Imports — Interview Questions
  • Collections Internals & Scenarios — Interview Questions
  • JVM, Memory & Class Loading — Interview Questions
  • Exception Design & Serialization Edge Cases — Interview Questions

Java 8 Deep Dive & Stream Coding

  • Lambdas, Functional Interfaces & Method References — Interview Questions
  • Default Methods, Backward Compatibility & Optional — Interview Questions
  • Stream API Internals (Part 1) — Interview Questions
  • Stream API Internals (Part 2) — Interview Questions
  • Stream Coding Problems (Level 2, Part 1) — Interview Questions
  • Stream Coding Problems (Level 2, Part 2) — Interview Questions

Concurrency & Multithreading

  • Synchronization, Locks & Deadlocks — Interview Questions
  • Executors, ThreadLocal & Concurrent Collections — Interview Questions

Spring Framework In Depth

  • Bean Lifecycle, Contexts & Circular Dependencies — Interview Questions
  • Spring Bean Conflicts, AOP, Batch & Injection Styles — Interview Questions

Spring Boot In Depth & Scenarios

  • Spring Boot Internals & Auto-Configuration — Interview Questions
  • Spring Boot Configuration, Profiles & Secrets — Interview Questions
  • Spring Boot Data, Transactions & Caching — Interview Questions
  • Spring Boot Testing, Error Pages & Deployment — Interview Questions
  • Spring Boot Performance, Scaling & Resilience — Interview Questions
  • Spring Boot Async, Events & Messaging — Interview Questions
  • Spring Boot Security Scenarios — Interview Questions
  • Actuator, AOP, Spring Cloud & Distributed Tracing — Interview Questions
  • External APIs, Files, GraphQL & WebFlux — Interview Questions

Spring Security

  • Spring Security — OAuth2, CORS, CSRF & Access Rules — Interview Questions
  • Spring Security — Passwords, Filter Chain, Sessions & Debugging — Interview Questions

Apache Kafka

  • Kafka Architecture, Topics & ZooKeeper vs KRaft — Interview Questions
  • Kafka Producers, Consumers, Reliability & Streams — Interview Questions
  • Kafka Security, Connect & Core Scenarios — Interview Questions
  • Kafka Production Scenarios — Interview Questions

Git, Maven & Gradle (Level II)

  • Git Workflows, Rebase & Conflict Handling — Interview Questions
  • Git Recovery, Hooks, Tags & Collaboration — Interview Questions
  • Maven Builds, Multi-Module Projects & Dependency Resolution — Interview Questions
  • Maven Profiles, settings.xml, Plugins & Quality Gates — Interview Questions
  • Gradle Fundamentals, Migration & Dependencies — Interview Questions
  • Gradle Performance, Plugins, Testing & Publishing — Interview Questions

Deployment & CI/CD

  • Sessions, CI/CD Pipelines, Rollbacks & Secrets — Interview Questions
  • Migrations, Zero-Downtime Releases, Containers & Monitoring — Interview Questions

JUnit 5 & Mockito

  • JUnit 5 — Interview Questions
  • Mockito Basics — Interview Questions
  • Mockito Advanced & Tricky Questions — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 2–5 YearsSpring Boot In Depth & Scenarios
✓ FreeIntermediate· 10 min read

External APIs, Files, GraphQL & WebFlux — Interview Questions

REST API versioning best practices, file-upload endpoints and where to store files, handling third-party rate limits and failures, cloud storage integration, a reactive API with WebFlux, consuming APIs with RestClient/WebClient, static plus dynamic pages, adding GraphQL, large uploads, and reactive consumption of external services.

Published September 25, 2026


How to use this lesson

These scenario questions test your integration judgement: which client, which storage, which API style, and how to stay up when a partner API misbehaves. Recommend the modern option first (RestClient, Spring for GraphQL, pre-signed URLs), and explain the trade-offs.

Q1. What are the best practices for versioning REST APIs in Spring Boot?

Short answer: Pick one strategy and apply it consistently. URI versioning (/api/v1/...) is the most common and operationally simplest. Header or media-type versioning (Accept: application/vnd.shop.v2+json) keeps URLs clean, but is harder to test and cache. Beyond the mechanism:

  • Version only for breaking changes, and evolve additively otherwise.
  • Support at most two or three live versions, with published deprecation and sunset dates (Deprecation and Sunset headers).
  • Keep an OpenAPI spec per version, and contract-test consumers.
  • Route versions at the gateway where possible.

Key points to cover:

  • Spring Framework 7 / Boot 4 add first-class API versioning (@GetMapping(path = "/orders", version = "2")), with configurable resolution by path, header or media type.

Learn it in depth → API Contract Design

Q2. You're building a file-upload endpoint. How do you handle the upload, and where do you store the files?

Short answer:

  • Handle: @PostMapping(consumes = MULTIPART_FORM_DATA_VALUE) with a MultipartFile. Validate the size, type (by magic bytes, not just the extension) and name. Stream the content (getInputStream()), never getBytes() for large files. Generate your own storage key.
  • Store: in object storage (S3, Azure Blob, GCS), not on the app server's disk (instances are ephemeral and horizontally scaled) or in database BLOBs (which bloat backups). Keep only metadata in the database: key, owner, size, content type, checksum.
  • Serve: through pre-signed URLs or a CDN, rather than streaming through the app.
  • Security: a malware scan, and authorisation on every download.

Learn it in depth → S3

Q3. Your app calls several external APIs. How do you handle their rate limits and failures?

Short answer: Wrap each client in its own resilience policy:

  • Timeouts: connect and read, per API.
  • Client-side rate limiting (Resilience4j RateLimiter, or a shared Redis bucket across instances), to stay under each provider's quota.
  • Retries with exponential backoff and jitter, only for idempotent calls and retryable errors (429, 503). Honour Retry-After.
  • Circuit breaker per provider, with fallbacks (cached data, or degraded features).
  • Bulkhead per provider, so one slow API can't exhaust the threads.
  • Caching of stable responses.
  • Queue-based smoothing for bulk jobs.
  • Monitoring of error rates and quota usage.
resilience4j:
  ratelimiter.instances.geoApi: { limit-for-period: 50, limit-refresh-period: 1s, timeout-duration: 200ms }
  retry.instances.geoApi: { max-attempts: 3, wait-duration: 500ms, enable-exponential-backoff: true }
  circuitbreaker.instances.geoApi: { failure-rate-threshold: 50, wait-duration-in-open-state: 30s }

Learn it in depth → Retry & Backoff Strategies

Q4. Multiple external APIs: how do you handle rate limits and failures? (Follow-up: what if the API is critical and has no fallback?)

Short answer: Then decouple in time. Accept the request, persist it, and process it asynchronously from a queue, retrying until the API recovers, while telling the user it's "processing". Add idempotency keys to your calls, so retries never duplicate side effects (payments, bookings). Alert when the queue backs up, and put failed requests into a dead-letter queue for manual handling.

Q5. How would you integrate cloud file storage into a Spring Boot app?

Short answer: Use the provider SDK (AWS SDK v2 S3Client, or Spring Cloud AWS's S3Template), wrapped in your own FileStorage interface, so the rest of the app doesn't depend on the vendor, and tests can use a fake or LocalStack.

public interface FileStorage {
    StoredFile put(String key, InputStream content, long size, String contentType);
    URL presignedDownload(String key, Duration ttl);
}

@Service
class S3FileStorage implements FileStorage {
    private final S3Client s3; private final S3Presigner presigner; private final String bucket;
    public StoredFile put(String key, InputStream in, long size, String type) {
        s3.putObject(b -> b.bucket(bucket).key(key).contentType(type), RequestBody.fromInputStream(in, size));
        return new StoredFile(key, size, type);
    }
    public URL presignedDownload(String key, Duration ttl) {
        return presigner.presignGetObject(p -> p.signatureDuration(ttl)
                .getObjectRequest(r -> r.bucket(bucket).key(key))).url();
    }
}

Key points to cover:

  • Credentials come from the platform identity (IAM roles for service accounts, instance profiles), never from access keys in application.yml.
  • Enable encryption at rest, lifecycle policies (moving cold files to cheaper tiers), and bucket policies that block public access.

Q6. How would you build a non-blocking, reactive REST API with Spring WebFlux?

Short answer: Use spring-boot-starter-webflux (Netty), with controllers that return Mono<T>/Flux<T>, and make the whole chain non-blocking:

  • R2DBC or reactive Mongo/Redis for data;
  • WebClient for outbound HTTP;
  • reactive Kafka if needed.

Handle back-pressure, use timeouts and retries with Reactor operators, and never block the event loop. Offload unavoidable blocking calls with subscribeOn(Schedulers.boundedElastic()).

@RestController
@RequestMapping("/api/prices")
class PriceController {
    private final PriceRepository prices;                     // ReactiveCrudRepository (R2DBC)
    private final WebClient fx;

    @GetMapping("/{sku}")
    Mono<PriceView> price(@PathVariable String sku, @RequestParam String currency) {
        return prices.findBySku(sku)
                .zipWith(fx.get().uri("/rates/{c}", currency).retrieve().bodyToMono(Rate.class))
                .map(t -> PriceView.of(t.getT1(), t.getT2()))
                .timeout(Duration.ofSeconds(2));
    }
}

Key points to cover:

  • WebFlux pays off for very high concurrency with mostly idle, I/O-bound connections (gateways, streaming, SSE). For typical CRUD services, Spring MVC on virtual threads gives comparable scalability, with simpler code and debugging.

Q7. How would you consume an external REST API: RestTemplate or WebClient?

Short answer: In new code, use neither by default:

  • RestClient (Spring 6.1+) is the modern synchronous client, with a fluent API.
  • HTTP interface clients (@HttpExchange) give declarative, Feign-like interfaces.
  • WebClient is for reactive or non-blocking applications.
  • RestTemplate still works, but it's in maintenance mode.
@Bean
RestClient catalogClient(RestClient.Builder builder) {        // Boot-configured builder (observability, converters)
    return builder.baseUrl("https://catalog.internal")
            .requestFactory(ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS
                    .withConnectTimeout(Duration.ofSeconds(2)).withReadTimeout(Duration.ofSeconds(3))))
            .build();
}

Product p = catalogClient.get().uri("/products/{id}", id)
        .retrieve()
        .onStatus(HttpStatusCode::is4xxClientError, (req, res) -> { throw new ProductNotFoundException(id); })
        .body(Product.class);

Key points to cover:

  • Always set timeouts. By default they're effectively infinite, which is how one slow partner exhausts all your threads.
  • Inject the Boot-provided builder, so tracing and metrics apply automatically.

Q8. Build a simple app with a static homepage and a dynamic page showing the server time. What's the project structure?

Short answer:

src/main/java/com/example/site/
    SiteApplication.java            (@SpringBootApplication)
    web/TimeController.java         (@Controller, GET /time)
src/main/resources/
    static/index.html               (served as-is at "/")
    static/css/site.css
    templates/time.html             (Thymeleaf view, rendered per request)
    application.yml
@Controller
class TimeController {
    private final Clock clock;
    TimeController(Clock clock) { this.clock = clock; }
    @GetMapping("/time")
    String time(Model model) {
        model.addAttribute("now", ZonedDateTime.now(clock));
        return "time";                                   // → templates/time.html
    }
}

Key points to cover:

  • spring-boot-starter-web plus spring-boot-starter-thymeleaf. static/index.html is served automatically as the welcome page.
  • Injecting a Clock makes the time page testable.

Q9. How would you add a GraphQL API to an existing Spring Boot REST service?

Short answer: Use Spring for GraphQL (spring-boot-starter-graphql), the official project built on GraphQL Java:

  1. Write the schema in src/main/resources/graphql/schema.graphqls.
  2. Implement controllers with @QueryMapping, @MutationMapping and @SchemaMapping, reusing your existing service layer.
  3. Prevent N+1 queries with @BatchMapping (DataLoader).
  4. Secure it with Spring Security (method security on resolvers).
  5. Limit query depth and complexity.
  6. Test with GraphQlTester, and explore with GraphiQL (spring.graphql.graphiql.enabled=true in development).
type Query { order(id: ID!): Order }
type Order { id: ID!, status: String!, customer: Customer! }
type Customer { id: ID!, name: String! }
@Controller
class OrderGraphQlController {
    @QueryMapping Order order(@Argument long id) { return orderService.find(id); }

    @BatchMapping Map<Order, Customer> customer(List<Order> orders) {            // one batched lookup, not N
        return customerService.findForOrders(orders);
    }
}

Common trap: "add the GraphQL Spring Boot starter" (the old third-party graphql-java-kickstart). Spring for GraphQL is the supported path today. REST and GraphQL can live side by side in the same app.

Q10. How do you handle large file uploads efficiently, and keep the system responsive?

Short answer: Don't route large files through your app servers at all:

  1. The client asks your API for a pre-signed upload URL, or a multipart upload.
  2. The client uploads directly to object storage, in resumable chunks.
  3. Storage emits an event (S3 → SQS/EventBridge), and a background worker scans, validates and processes the file (thumbnails, parsing).
  4. The API tracks the status (UPLOADING → PROCESSING → READY).

If files must pass through the app: stream them (no buffering in memory), set multipart size limits and disk thresholds, use async processing, and put limits on concurrency.

Q11. How do you consume an external service with WebFlux, and process the data reactively?

Short answer: Use WebClient to get a Flux or Mono, then compose operators: map, filter, flatMap with bounded concurrency, buffer/window for batching, and timeout, retryWhen(Retry.backoff(...)) and onErrorResume for resilience. Back-pressure flows from the subscriber to the source.

Flux<Product> enriched = webClient.get().uri("/products?since={t}", since)
        .retrieve()
        .bodyToFlux(ProductDto.class)                                  // streamed (NDJSON or JSON array)
        .filter(ProductDto::active)
        .flatMap(dto -> pricing.priceFor(dto.sku()).map(dto::withPrice), 16)   // at most 16 concurrent lookups
        .timeout(Duration.ofSeconds(10))
        .retryWhen(Retry.backoff(3, Duration.ofMillis(200)).filter(this::isTransient))
        .onErrorResume(e -> Flux.empty());

enriched.buffer(500).concatMap(repository::saveAll).subscribe();     // write in batches, sequentially

Key points to cover:

  • Nothing happens until subscription. In a WebFlux controller, the framework subscribes when you return the Flux.
  • Avoid .block() inside reactive flows. It defeats the model, and can deadlock the event loop.

Follow-up questions this topic invites — and their answers

Q: What's the difference between Mono and Flux? A: Mono emits 0 or 1 items, then completes or errors. Flux emits 0 to N items (possibly infinite). Both are lazy publishers, with back-pressure.

Q: When is GraphQL a better fit than REST? A: When many clients need different shapes of related data (mobile vs web), and you want to avoid over-fetching and chains of calls. It adds complexity in caching (no simple HTTP caching), rate limiting (by query cost) and N+1 prevention.

Q: How do you test code that calls an external API? A: Unit-test the client with MockRestServiceServer (RestClient/RestTemplate), or WireMock. Add contract tests with the provider where possible. Test timeouts and error mapping, not just the happy path.

Q: What's a pre-signed URL? A: A time-limited URL, signed with your credentials, that lets a client upload or download one specific object directly from object storage, without giving them any cloud credentials.

Previous

Actuator, AOP, Spring Cloud & Distributed Tracing — Interview Questions

Next

Spring Security — OAuth2, CORS, CSRF & Access Rules — Interview Questions

AI Tutor

Lesson: External APIs, Files, GraphQL & WebFlux — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.