HTTP, REST & RestTemplate
HTTP protocol fundamentals, REST architecture, Spring RestTemplate for GET/POST/PUT/DELETE, exchange(), and ResponseEntity handling.
Assumes you know
After this you should be able to
- Explain the core idea in HTTP, REST & RestTemplate
- Apply HTTP, REST & RestTemplate in a representative exercise
My working notes on how machines talk over the web: the HTTP protocol, its methods and status codes, the
REST architectural style, and calling APIs from Java with Spring's RestTemplate (GET JSON
→ object, plus downloading a file).
Notebook Summary copy by hand#
Terse cheat sheet. Lead with the term, then the rule. Doodles are ~10-second sketches.
HTTP — basics#
HTTP = HyperText Transfer Protocol
= application-layer protocol, transfers data btwn machines over internet
= request -> response (client asks, server answers)
= stateless (each req independent, server keeps no memory) [+]
= text-based, runs over TCP (port 80); HTTPS = HTTP+TLS (port 443) [+]
req shape: METHOD /path HTTP/1.1
Headers (Accept, Content-Type, Authorization...)
[blank line]
Body (optional)
resp shape: HTTP/1.1 STATUS_CODE reason
Headers
[blank line]
BodyHTTP methods#
GET -> fetch resource (page/img/json/xml). no body. safe + idempotent
POST -> create new resource / submit form / upload. NOT idempotent
PUT -> update resource at KNOWN location (full replace). idempotent
(can also create if endpoint supports that id)
DELETE -> remove resource. idempotent
PATCH -> partial update [+]
HEAD -> like GET but headers only, no body [+]
OPTIONS-> ask what methods/CORS allowed [+]
also: CONNECT, TRACEPUT vs POST (very common Q)#
POST -> CREATE new resource, server picks location/id -> not idempotent
PUT -> UPDATE at known URL (replace) -> idempotent
(PUT may create if API supports client-set id)
idempotent = same call N times == same call 1 time (no extra effect)
GET PUT DELETE HEAD OPTIONS = idempotent ; POST PATCH = not [+]
doodle: POST = mailbox you drop letter in (server files it)
PUT = whiteboard cell, you overwrite exact spotStatus codes — the 5 buckets#
1xx "not done yet" informational
2xx "you win" success
3xx "lose, try again" redirection
4xx "lose, your fault" client error
5xx "lose, my fault" server error| Code | Meaning | When |
|---|---|---|
200 | OK | generic success (GET ok) |
201 | Created [+] | POST/PUT made a resource |
204 | No Content | success, empty body (often DELETE) |
301 | Moved Permanently | URL changed for good |
302 | Moved Temporarily | temp redirect |
304 | Not Modified | use your cached copy |
400 | Bad Request | malformed input |
401 | Unauthorized | not authenticated [+] |
403 | Forbidden [+] | authd but not allowed |
404 | Not Found | no such resource |
500 | Internal Server Error | server blew up |
memory: 401 = "who are you?" (login) 403 = "I know you, NO." [+]REST#
REST = REpresentational State Transfer
= architectural STYLE (not a protocol), usually over HTTP
= everything is a RESOURCE, addressed by a URL (endpoint)
= client-server, modular, stateless [+]
= act on resources via HTTP methods (GET/POST/PUT/DELETE)
endpoint = the URL that names a resource
GET /api/users -> list
GET /api/users/42 -> one
POST /api/users -> create
PUT /api/users/42 -> update
DELETE /api/users/42 -> delete [+]
resource vs representation: resource = the "thing";
representation = a form of it (JSON, XML, HTML) [+]| HTTP | REST | |
|---|---|---|
| What | protocol (rules of transfer) | style (how to design APIs) |
| Level | transport mechanism | architecture on top |
| Relation | NOT the same. REST usually rides on HTTP, but could use another protocol. [+] | |
Spring RestTemplate — GET JSON → object#
RestTemplate = Spring's synchronous HTTP client (blocking) [+]
flow (Activity 1, GET /api/random):
client --GET--> server
header Accept: application/json
server --200 + JSON body--> client
JSON --(HttpMessageConverter / Jackson)--> Quote object (deserialize)
key call:
Quote q = restTemplate.getForObject(url, Quote.class);
doodle: [JSON text] -> (Jackson funnel) -> [Quote {} object]
note: RestTemplate is in maintenance mode; new code -> WebClient/RestClient [+]| RestTemplate method | Does |
|---|---|
getForObject | GET, returns body as object |
getForEntity | GET, returns ResponseEntity (body+status+headers) |
postForObject | POST, returns created body |
put | PUT, no return |
delete | DELETE |
exchange | any method, full control [+] |
Download a file (Activity 2)#
get bytes: byte[] data = restTemplate.getForObject(url, byte[].class);
Files.write(Path.of("out.bin"), data); // small files OK
big files: use exchange + ResponseExtractor -> stream to disk (no OOM) [+]
doodle: server file -> [bytes stream] -> disk (avoid loading all in RAM)Detailed Study Notes#
+ marks anything I added or corrected beyond the core material. Code cross-links jump to Part III.
1. HTTP is the language machines use to move data across the web#
HTTP (HyperText Transfer Protocol) is an application-layer protocol that lets machines anywhere on the internet exchange data. When a browser loads a page, a mobile app fetches data, or one server calls another, it almost always happens over HTTP. "Application-layer" means it sits at the top of the networking stack and deals with the content of the conversation (give me this page, here is your JSON), while lower layers (TCP/IP) handle the plumbing of actually shipping the bytes.
The model is dead simple: a client sends a request, a server sends back a response. Always paired. The client always starts the conversation; the server never speaks first.
+HTTP is stateless: each request is
self-contained and the server keeps no memory of previous requests. That is why apps re-send
identity on every call (a cookie, a token in the Authorization header). Statelessness
is what makes web servers easy to scale, you can route any request to any server.
+HTTP is text-based and rides on top of
TCP (default port 80). HTTPS is the same protocol wrapped in TLS
encryption (default port 443). Everything below is identical; HTTPS just makes the pipe
private and tamper-evident.
A request has four parts: a start line (GET /path HTTP/1.1), headers (metadata
like Accept, Content-Type, Authorization), a blank line, and an
optional body. A response mirrors it: a status line (HTTP/1.1 200 OK),
headers, blank line, body. See the raw shape in Code §1.
2. HTTP methods name the action you want to take#
Every HTTP request carries a method (a "verb") that tells the server what kind of operation you intend. The core four for everyday API work:
- GET — fetch a resource. Used to retrieve web pages, images, JSON, XML, etc. A GET has no body; everything it needs is in the URL. + GET is safe (read-only, never changes server state) and idempotent.
- POST — submit data to create something or trigger processing: login form data, a ticket-reservation form, an image upload. Carries a body. + POST is not idempotent, sending it twice can create two records.
- PUT — update the resource at a known location (e.g. change a password or address). It replaces the resource at that URL. + PUT is idempotent: PUT the same body 5 times and the end state is identical to doing it once.
- +DELETE — remove a resource; idempotent (gone stays gone).
Other methods exist for special cases: HEAD, DELETE, OPTIONS, CONNECT, TRACE, PATCH.
+Quick read on the less-common ones: HEAD = a GET that returns only headers (no body), handy to check size or existence cheaply. OPTIONS = "what can I do here?" (used by browser CORS preflight). PATCH = a partial update (change one field) vs PUT's full replace. CONNECT sets up a tunnel (HTTPS through a proxy); TRACE echoes the request for debugging (usually disabled for security).
| Method | Purpose | Body? | Safe | Idempotent |
|---|---|---|---|---|
GET | read | no | yes | yes |
POST | create / process | yes | no | no |
PUT | replace at URL | yes | no | yes |
PATCH + | partial update | yes | no | no* |
DELETE + | remove | opt | no | yes |
3. PUT vs POST: create at server's choice vs update at a known spot#
Use POST to create a new resource; use PUT to update a resource at a location you already know. The deciding question is: do you know the final URL of the resource?
- POST when creating a new resource and you let the server decide its
identity/location. Example:
POST /api/orders→ server creates order #5821 and tells you where it lives. - PUT when updating a resource at a known location:
PUT /api/users/42replaces user 42's data. - A new resource can be created with PUT too, if the API endpoint supports it, because
the client supplies the exact id (e.g.
PUT /api/users/42where the client chose "42").
The cleanest mental model is idempotency. POST twice → possibly two resources. PUT twice with the same body → one resource in one final state. + That is exactly why payment/order-creation endpoints worry about double-submits (POST), while "set my profile to X" endpoints are safe to retry (PUT).
4. Status codes: the server's one-word verdict on your request#
Every response carries a 3-digit status code that classifies the outcome. The first digit puts it in one of five buckets, an easy way to remember the whole space:
| Class | Nickname | Meaning |
|---|---|---|
1xx | "not done yet" | Informational, request received, keep going |
2xx | "you win" | Success |
3xx | "lose, try again" | Redirection, more steps needed |
4xx | "lose, your fault" | Client error, the request was wrong |
5xx | "lose, my fault" | Server error, the server failed |
The codes worth memorizing: 200 OK, 204 No Content, 300 Multiple Choices, 301 Moved Permanently, 302 Moved Temporarily, 304 Not Modified, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error.
+Three more that come up constantly in real APIs:
201 Created (a POST/PUT successfully made a resource, often with a Location
header), 403 Forbidden (you're authenticated but not allowed), and 429 Too Many
Requests (rate-limited).
5. REST is a style for designing APIs around resources#
REST (REpresentational State Transfer) is an architectural style: it's about resources and the different ways to access them. It is not a protocol or a library, it's a set of design conventions, and in practice those conventions are implemented over HTTP.
The central idea: model your system as resources (users, orders, quotes) each addressable by a URL, and act on them with HTTP methods. REST embraces a modular client–server architecture, the client and server are decoupled and can evolve independently as long as they agree on the resource contract.
+The fundamental constraints of REST are worth knowing by name: client–server (separation of concerns), stateless (each request self-contained), cacheable (responses say whether they can be cached), uniform interface (consistent resource URLs + standard methods), and layered system (proxies/load balancers can sit in between invisibly). An API following these is "RESTful."
+Resource vs representation: the resource is the
abstract "thing" (user #42). A representation is a concrete encoding of it returned to you,
JSON, XML, or HTML. Same resource, multiple representations. The client says which it wants via the
Accept header.
REST endpoints#
An endpoint is the URL that names a resource. A conventional CRUD design looks like:
| Method + Endpoint | Action |
|---|---|
GET /api/users | list all users |
GET /api/users/42 | get one user |
POST /api/users | create a user |
PUT /api/users/42 | update user 42 |
DELETE /api/users/42 | delete user 42 |
GET /api/v1/orders/{id}, you instantly know what
it does, no docs needed. That predictability is the whole point of the style.6. HTTP and REST are not the same thing#
HTTP is a protocol; REST is an architectural style. They are different layers, and REST merely usually rides on HTTP. This is a classic "gotcha" question, and the answer is a firm no, they are not the same.
- HTTP = the concrete rules for transferring data (methods, headers, status codes, the request/response format). A mechanism.
- REST = a set of design principles for building APIs (resources, statelessness, uniform interface). An idea about how to use a transport.
+ You can speak HTTP without being RESTful (e.g. an RPC-style endpoint that ignores resource conventions), and in theory REST principles could be applied over a non-HTTP transport. In the real world, "REST API" almost always means "RESTful design implemented over HTTP," which is why the two get conflated.
7. Activity 1 — GET a quote: from JSON over the wire to a Java object#
This is the full round-trip of a REST GET in Java: make the request, receive JSON, and turn that JSON
into a typed object. Concretely, we hit
GET https://quoters.apps.pcfone.io/api/random and want the result as a Quote
object.
Step by step, here is what happens:
- Make an HTTP GET request to the random-quote endpoint.
- Send
Accept: [application/json, application/*+json], the client telling the server "give me JSON." - Receive a response in JSON format with success (
200 OK). - Deserialize the JSON body into a
com.example.Quoteobject using a message converter (anHttpMessageConverter), which under the hood uses the Jackson library for JSON processing.
+Deserialization = converting bytes/text (JSON)
into in-memory objects. The reverse, object → JSON, is serialization. Jackson maps JSON
keys to Java fields by name (or via annotations like @JsonProperty). For Jackson to
build your object it generally needs a no-arg constructor and matching field names, or it'll throw
an "Unrecognized field" / "Cannot construct instance" error.
Quote.class argument as the assembly instructions. Jackson is the worker that
reads the instructions and builds the actual chair (object) you can sit on (use in code).In Spring this entire flow is one line via RestTemplate:
Quote q = restTemplate.getForObject(url, Quote.class);Full runnable version with the matching model class is in Code §2.
HttpMessageConverters. For JSON,
MappingJackson2HttpMessageConverter uses Jackson's ObjectMapper to bind the
body to your class, chosen based on the response's Content-Type.8. Spring RestTemplate: a synchronous HTTP client for Java#
RestTemplate is Spring's high-level, blocking HTTP client, it wraps the tedious work of
opening connections, setting headers, sending the request, reading the response, and converting
bodies. Instead of hand-rolling sockets or verbose HttpURLConnection code, you call
one method per HTTP verb.
The method names map directly onto HTTP methods:
| Method | HTTP verb | What it returns |
|---|---|---|
getForObject(url, Type) | GET | the body, converted to Type |
getForEntity(url, Type) | GET | ResponseEntity (body + status + headers) |
postForObject(url, body, Type) | POST | the created resource body |
put(url, body) | PUT | void |
delete(url) | DELETE | void |
exchange(...) + | any | full control: set method, headers, get ResponseEntity |
+ Use getForObject when you only care about the body; use
getForEntity when you also need the status code or response headers (e.g. to read a
Location or check for 304). Use exchange when you need to send
custom headers (like an Authorization token) or use a verb the convenience methods don't
cover.
RestTemplate is in maintenance mode as of Spring 5, it still works and is everywhere
in existing code, but for new projects Spring recommends the reactive WebClient or the
newer synchronous RestClient (Spring 6.1+). For learning the request/response flow,
RestTemplate is still the clearest tool. + Also note: by default
a 4xx/5xx response throws a RestClientException (e.g.
HttpClientErrorException) rather than returning the body, so wrap calls in try/catch when
errors are expected.RestTemplate is the
on-ramp: master it and the concepts (converters, entities, headers, error handling) carry straight over
to WebClient/RestClient.9. Activity 2 — downloading a file with RestTemplate#
To download a file, fetch the response body as raw bytes and write them to disk. The simplest form
treats the body as a byte[]:
byte[] data = restTemplate.getForObject(url, byte[].class);
Files.write(Path.of("output.bin"), data);This works fine for small files. + The catch:
getForObject(..., byte[].class) loads the entire file into memory first. For large
files that risks an OutOfMemoryError. The robust pattern is to use
execute/exchange with a ResponseExtractor that streams the response
InputStream straight to a file (e.g. StreamUtils.copy /
Files.copy), so memory stays flat regardless of file size. Full streaming example in Code §3.
byte[]; use a
ResponseExtractor to stream the body's InputStream directly to disk.Key Takeaways#
- HTTP is a stateless, application-layer request/response protocol; the client always initiates.
- Methods name intent: GET (read), POST (create), PUT (replace at known URL), plus PATCH/DELETE/HEAD/OPTIONS. Know safe vs idempotent.
- PUT vs POST: POST creates (server-chosen location, not idempotent); PUT updates at a known URL (idempotent), and can create when the client sets the id.
- Status codes in five buckets: 1xx info, 2xx success, 3xx redirect, 4xx client error, 5xx server error. Memorize 200/204/301/302/304/400/401/404/500 (+201/403).
- REST is an architectural style around resources addressed by URLs, acted on via HTTP methods, in a stateless client-server design. REST ≠ HTTP.
- RestTemplate is Spring's synchronous HTTP client;
getForObject+ Jackson (via HttpMessageConverter) turns JSON into typed objects. It's in maintenance mode, newer code uses WebClient/RestClient. - Downloading files:
byte[]for small, stream via ResponseExtractor for large.
Code Samples#
Runnable Java 17. Pure JDK where possible; Spring/Jackson only where the activity needs them. Each block: file, run command, comments, expected output.
1. The raw HTTP envelope (no library)#
To see the request/response shape, here's a request built and sent with the JDK's built-in
HttpClient (Java 11+), no Spring needed.
RawHttp.javajava RawHttp.javaimport java.net.URI; import java.net.http.*; // JDK built-in HTTP client public class RawHttp { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); // Build a GET request. Method + URL + headers = the request line/headers. HttpRequest req = HttpRequest.newBuilder().uri(URI.create("https://quoters.apps.pcfone.io/api/random")) .header("Accept", "application/json") // "give me JSON" .GET() // the HTTP method .build(); HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println("Status: " + res.statusCode()); // 200 System.out.println("Body: " + res.body()); // raw JSON text } }Expected outputStatus: 200 / Body: {"type":"success","value":{"id":..,"quote":".."}}
java.net.http.HttpClient in the JDK, so this needs no dependencies.2. Activity 1 — GET → deserialize into a Quote (Spring RestTemplate + Jackson)#
First the model class. Field names match the JSON keys so Jackson can bind them automatically.
Quote.javapart of the session-3 projectpackage com.crio.session3.activity1; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; // Ignore any JSON keys we didn't model (defensive, avoids crashes). [+] @JsonIgnoreProperties(ignoreUnknown = true) public class Quote { private String type; // maps JSON "type": "success" private Value value; // nested object "value": {..} // No-arg constructor + getters/setters let Jackson populate the object. [+] public Quote() {} public String getType() { return type; } public void setType(String t) { this.type = t; } public Value getValue() { return value; } public void setValue(Value v) { this.value = v; } @JsonIgnoreProperties(ignoreUnknown = true) public static class Value { private Long id; private String quote; // the actual quote text public Value() {} public Long getId() { return id; } public void setId(Long i) { this.id = i; } public String getQuote() { return quote; } public void setQuote(String q) { this.quote = q; } } }
QuoteRunner.java./mvnw spring-boot:run (or run main)package com.crio.session3.activity1; import org.springframework.web.client.RestTemplate; public class QuoteRunner { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); String url = "https://quoters.apps.pcfone.io/api/random"; // ONE line does: GET -> receive JSON -> Jackson deserializes -> Quote object Quote quote = restTemplate.getForObject(url, Quote.class); System.out.println("type: " + quote.getType()); System.out.println("quote: " + quote.getValue().getQuote()); } }Expected outputtype: success / quote: Spring Boot solves this problem... (a random quote)
getForObject(url, Quote.class) picks the
MappingJackson2HttpMessageConverter because the response Content-Type is JSON,
then Jackson's ObjectMapper matches JSON keys to fields by name. + If a JSON key has no matching field and you didn't add
@JsonIgnoreProperties(ignoreUnknown=true), Jackson throws
UnrecognizedPropertyException, that's the #1 beginner error here.3. Activity 2 — download a file (simple + streaming)#
DownloadSimple.javasmall files onlyimport org.springframework.web.client.RestTemplate; import java.nio.file.*; public class DownloadSimple { public static void main(String[] args) throws Exception { RestTemplate rt = new RestTemplate(); String url = "https://example.com/sample.pdf"; // Body comes back as raw bytes (loaded fully into memory). byte[] bytes = rt.getForObject(url, byte[].class); Files.write(Path.of("sample.pdf"), bytes); // write to disk System.out.println("Saved " + bytes.length + " bytes"); } }Expected outputSaved 53241 bytes (file sample.pdf appears in the working dir)
DownloadStream.javasafe for large files [+]import org.springframework.http.HttpMethod; import org.springframework.util.StreamUtils; import org.springframework.web.client.RestTemplate; import java.io.*; import java.nio.file.*; public class DownloadStream { public static void main(String[] args) { RestTemplate rt = new RestTemplate(); String url = "https://example.com/big-file.zip"; // ResponseExtractor streams the body straight to disk -> flat memory. [+] rt.execute(url, HttpMethod.GET, null, response -> { Path out = Path.of("big-file.zip"); try (OutputStream os = Files.newOutputStream(out)) { StreamUtils.copy(response.getBody(), os); // stream copy } return out; }); System.out.println("Downloaded via streaming"); } }Expected outputDownloaded via streaming (big-file.zip written without buffering it all in RAM)
byte[] form is
convenient but the whole file lives in memory before writing. The execute(...) +
ResponseExtractor form gets the response InputStream and copies it
chunk-by-chunk to an OutputStream, so memory use stays roughly constant no matter the file
size.Hands-On Lab#
Predict-then-verify drills. Warm-up → Core → Challenge. Solutions are collapsed, try first.
# 1. Java 17 installed?
java -version # expect "17.x" (Java 11+ ok for plain HttpClient)
# 2. Clone your project repo into your workspace
cd ~/workspace
git clone <your-repo-url>
# already cloned? -> git pull origin main
# 3. Open the project folder; wait for the Java Language Server to finish.
# 4. Single-file programs (no Spring) run directly with Java 11+:
java RawHttp.java
# 5. Spring activities run through the project's build:
./mvnw spring-boot:run # or run the main() from your IDEClassify any status code by its first digit#
Goal: internalize the five buckets without a lookup table.
- Write a method
classify(int code)returning the bucket name. - Test it with 204, 301, 404, 500, 100.
classify(204) and
classify(301) print before you run it?Solution
Classify.javajava Classify.javapublic class Classify { static String classify(int code) { return switch (code / 100) { // integer-divide -> first digit case 1 -> "1xx informational"; case 2 -> "2xx success"; case 3 -> "3xx redirection"; case 4 -> "4xx client error"; case 5 -> "5xx server error"; default -> "unknown"; }; } public static void main(String[] a) { for (int c : new int[]{204,301,404,500,100}) System.out.println(c + " -> " + classify(c)); } }Expected output204 -> 2xx success / 301 -> 3xx redirection / 404 -> 4xx client error / 500 -> 5xx server error / 100 -> 1xx informational
Make a raw GET and read the status line#
Goal: confirm the request/response envelope with your own eyes.
- Use the JDK
HttpClientto GEThttps://quoters.apps.pcfone.io/api/random. - Print only the status code and the first 80 chars of the body.
Solution
It's a string of JSON, nothing has deserialized it yet; that step comes only with Jackson/RestTemplate.
PeekGet.javajava PeekGet.javaimport java.net.URI; import java.net.http.*; public class PeekGet { public static void main(String[] a) throws Exception { var res = HttpClient.newHttpClient().send(HttpRequest.newBuilder(URI.create("https://quoters.apps.pcfone.io/api/random")) .header("Accept","application/json").build(), HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode()); System.out.println(res.body().substring(0, Math.min(80, res.body().length()))); } }Expected output200 / {"type":"success","value":{"id":..,"quote":"...
Deserialize JSON into a Quote with RestTemplate#
Goal: reproduce Activity 1, JSON → typed object.
- Create the
Quotemodel (fieldstype, nestedvalue.quote). - Call
getForObject(url, Quote.class)and print the quote text.
author with no matching field
and you didn't set ignoreUnknown=true, what happens?Solution
Without @JsonIgnoreProperties(ignoreUnknown=true), Jackson throws
UnrecognizedPropertyException. With it, the extra key is silently skipped. Full
code in Code §2.
QuoteRunner.javarun main()RestTemplate rt = new RestTemplate(); Quote q = rt.getForObject( "https://quoters.apps.pcfone.io/api/random", Quote.class); System.out.println(q.getValue().getQuote());Expected outputA random quote string, e.g. "Spring Boot solves this problem..."
Read status + headers with getForEntity#
Goal: see when you need ResponseEntity instead of just the body.
- Swap
getForObjectforgetForEntity(url, Quote.class). - Print the status code and the
Content-Typeheader alongside the quote.
Content-Type do you expect, and which status
code?Solution
Expect 200 OK and application/json. getForEntity gives
you the whole response, not just the body.
EntityRunner.javarun main()import org.springframework.http.ResponseEntity; // ... ResponseEntity<Quote> resp = rt.getForEntity(url, Quote.class); System.out.println(resp.getStatusCode()); // 200 OK System.out.println(resp.getHeaders().getContentType()); // application/json System.out.println(resp.getBody().getValue().getQuote());Expected output200 OK / application/json / (the quote text)
Handle a 404 gracefully#
Goal: learn that RestTemplate throws on 4xx/5xx by default.
- GET a deliberately wrong path (e.g.
.../api/does-not-exist). - Catch the exception and print the status code instead of crashing.
getForObject return null on a 404,
or throw? Which exception type?Solution
It throws HttpClientErrorException.NotFound (a subclass of
HttpClientErrorException → RestClientException). It does not
return null.
NotFoundDemo.javarun main()import org.springframework.web.client.HttpClientErrorException; // ... try { rt.getForObject("https://quoters.apps.pcfone.io/api/does-not-exist", String.class); } catch (HttpClientErrorException e) { System.out.println("Got error status: " + e.getStatusCode()); }Expected outputGot error status: 404 NOT_FOUND
Stream a download to disk without buffering it all#
Goal: implement the memory-safe download from Activity 2.
- Use
rt.execute(url, HttpMethod.GET, null, extractor). - In the extractor, copy
response.getBody()(anInputStream) to a file viaStreamUtils.copy. - Print the final file size from disk to confirm it wrote.
getForObject(url, byte[].class), how does
peak memory differ for a 1 GB file?Solution
The byte[] version holds ~1 GB in heap at once (likely
OutOfMemoryError). The streaming version copies in small chunks, so peak memory
stays small and constant. Full code in Code
§3.
StreamDownload.javarun main()rt.execute(url, HttpMethod.GET, null, response -> { Path out = Path.of("download.bin"); try (var os = Files.newOutputStream(out)) { StreamUtils.copy(response.getBody(), os); // chunked copy } return out; }); System.out.println(Files.size(Path.of("download.bin")) + " bytes");Expected outpute.g. 1048576 bytes (file written; heap stays flat)
Self-check rubric, "how do I know I've got it?"#
- I can describe the request/response envelope and name 4 headers without looking.
- Given a status code, I instantly state its bucket and, for the common ones, its exact meaning (esp. 401 vs 403, 301 vs 302).
- I can argue when to use PUT vs POST using idempotency, not just "create vs update."
- I can explain, in one breath, how
getForObject+ Jackson turns JSON into aQuote, and what breaks if a field is missing. - I can state why REST ≠ HTTP and give one example of HTTP-without-REST.
- I can choose between
byte[]and streaming for a download and justify it by file size/memory.