Study Notes
Data & I/Oapplied

HTTP, REST & RestTemplate

HTTP protocol fundamentals, REST architecture, Spring RestTemplate for GET/POST/PUT/DELETE, exchange(), and ResponseEntity handling.

30 min read·verified Content review 2026·reviewed 2026-08-30

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
HTTP MethodsREST APIRestTemplate

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).

HTTP REST RestTemplate Jackson / JSON Java 17
Part I

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]
            Body

HTTP 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, TRACE

PUT 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 spot

Status 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
CodeMeaningWhen
200OKgeneric success (GET ok)
201Created [+]POST/PUT made a resource
204No Contentsuccess, empty body (often DELETE)
301Moved PermanentlyURL changed for good
302Moved Temporarilytemp redirect
304Not Modifieduse your cached copy
400Bad Requestmalformed input
401Unauthorizednot authenticated [+]
403Forbidden [+]authd but not allowed
404Not Foundno such resource
500Internal Server Errorserver 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) [+]
HTTPREST
Whatprotocol (rules of transfer)style (how to design APIs)
Leveltransport mechanismarchitecture on top
RelationNOT 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 methodDoes
getForObjectGET, returns body as object
getForEntityGET, returns ResponseEntity (body+status+headers)
postForObjectPOST, returns created body
putPUT, no return
deleteDELETE
exchangeany 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)
Part II

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.

Why it mattersNearly every backend task, REST APIs, microservices, webhooks, OAuth, is just structured HTTP. Once you can picture the request/response envelope, debugging "why did my API call fail" becomes reading headers and status codes instead of guessing.
Common misconceptionHTTP is not the web pages themselves and not HTML. HTML is one kind of content you can move; HTTP is the delivery mechanism. You can ship JSON, images, video, or raw bytes over the exact same protocol.

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).

Interview angleKnow safe vs idempotent. Safe = no side effects (GET, HEAD, OPTIONS). Idempotent = repeating the call has the same effect as one call (GET, PUT, DELETE, HEAD, OPTIONS). POST and PATCH are neither guaranteed safe nor idempotent. This is a favorite distinction.
MethodPurposeBody?SafeIdempotent
GETreadnoyesyes
POSTcreate / processyesnono
PUTreplace at URLyesnoyes
PATCH +partial updateyesnono*
DELETE +removeoptnoyes

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/42 replaces 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/42 where 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).

AnalogyPOST = dropping a letter in a mailbox: the post office assigns it a place and you can't predict exactly where. PUT = writing into a specific labeled cell on a whiteboard: you know the cell, and rewriting the same value leaves it unchanged.
Interview angle"When would you use PUT to create?" → When the client controls the resource id and the endpoint allows it, so the URL is known in advance and the operation stays idempotent.

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:

ClassNicknameMeaning
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).

Don't confuse 401 vs 403401 Unauthorized actually means unauthenticated: "I don't know who you are, log in." 403 Forbidden means "I know who you are, and you still can't have this." + The naming is a historical quirk, but the distinction is real and frequently tested.
Interview angle"Difference between 301 and 302?" → 301 is permanent (clients/search engines should update the URL and cache the redirect); 302 is temporary (keep using the original URL). "What does 304 do for you?" → It powers caching: the server says "your cached copy is still valid," saving a full re-download.

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 + EndpointAction
GET /api/userslist all users
GET /api/users/42get one user
POST /api/userscreate a user
PUT /api/users/42update user 42
DELETE /api/users/42delete user 42
Why it mattersRESTful conventions are the lingua franca of web APIs. When you join a project and see 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.

Interview angleIf asked "Is REST the same as HTTP?" the strong answer is: "No. HTTP is the transport protocol; REST is an architectural style that defines how to design APIs, typically using HTTP methods and status codes, but the two operate at different levels of abstraction."

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:

  1. Make an HTTP GET request to the random-quote endpoint.
  2. Send Accept: [application/json, application/*+json], the client telling the server "give me JSON."
  3. Receive a response in JSON format with success (200 OK).
  4. Deserialize the JSON body into a com.example.Quote object using a message converter (an HttpMessageConverter), 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.

AnalogyThink of the JSON text as flat-pack furniture in a box and the 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.

Interview angle"How does Spring turn a JSON response into my object?" → Via 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:

MethodHTTP verbWhat it returns
getForObject(url, Type)GETthe body, converted to Type
getForEntity(url, Type)GETResponseEntity (body + status + headers)
postForObject(url, body, Type)POSTthe created resource body
put(url, body)PUTvoid
delete(url)DELETEvoid
exchange(...) +anyfull 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.

Pitfall / good to know+ 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.
Why it mattersCalling other services is the daily reality of backend work (microservices, third-party APIs, payment gateways). 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.

Trade-offbyte[] approach: tiny, readable, fine for small assets, but memory grows with file size. Streaming approach: a few more lines, but constant memory and safe for gigabyte downloads. Pick based on expected file size.
Interview angle"How would you download a 2 GB file with RestTemplate without running out of memory?" → Don't buffer it as a 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.
Part III

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.java
import 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":".."}}
Why it behaves this wayThe body comes back as a string of JSON, exactly the bytes on the wire. Nothing has parsed it into an object yet. That parsing step is what Jackson/RestTemplate add in §2. + Java 11+ ships 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 project
package 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)
Why it behaves this waygetForObject(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 only
import 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)
Why it behaves this wayThe 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.
Part IV

Hands-On Lab#

Predict-then-verify drills. Warm-up → Core → Challenge. Solutions are collapsed, try first.

Warm-up · 1

Classify any status code by its first digit#

Goal: internalize the five buckets without a lookup table.

  1. Write a method classify(int code) returning the bucket name.
  2. Test it with 204, 301, 404, 500, 100.
Predict: what should classify(204) and classify(301) print before you run it?
Solution
Classify.javajava Classify.java
public 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
Warm-up · 2

Make a raw GET and read the status line#

Goal: confirm the request/response envelope with your own eyes.

  1. Use the JDK HttpClient to GET https://quoters.apps.pcfone.io/api/random.
  2. Print only the status code and the first 80 chars of the body.
Predict: will the body be a Java object or a string of JSON at this point? Why?
Solution

It's a string of JSON, nothing has deserialized it yet; that step comes only with Jackson/RestTemplate.

PeekGet.javajava PeekGet.java
import 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":"...
Core · 3

Deserialize JSON into a Quote with RestTemplate#

Goal: reproduce Activity 1, JSON → typed object.

  1. Create the Quote model (fields type, nested value.quote).
  2. Call getForObject(url, Quote.class) and print the quote text.
Predict: if the JSON had a key 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..."
Core · 4

Read status + headers with getForEntity#

Goal: see when you need ResponseEntity instead of just the body.

  1. Swap getForObject for getForEntity(url, Quote.class).
  2. Print the status code and the Content-Type header alongside the quote.
Predict: which 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)
Core · 5

Handle a 404 gracefully#

Goal: learn that RestTemplate throws on 4xx/5xx by default.

  1. GET a deliberately wrong path (e.g. .../api/does-not-exist).
  2. Catch the exception and print the status code instead of crashing.
Predict: does 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
Challenge · 6

Stream a download to disk without buffering it all#

Goal: implement the memory-safe download from Activity 2.

  1. Use rt.execute(url, HttpMethod.GET, null, extractor).
  2. In the extractor, copy response.getBody() (an InputStream) to a file via StreamUtils.copy.
  3. Print the final file size from disk to confirm it wrote.
Predict: compared to 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 a Quote, 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.