You want to ship an API. You don’t want to hand-configure Tomcat, write a web.xml, or fight a servlet container. A Spring Boot REST controller gets you from zero to a working HTTP endpoint in about five minutes — and this guide is the copy-paste-run version, plus just enough explanation that you actually understand what you pasted.
What you need first
One dependency: spring-boot-starter-web. Add it to your pom.xml (or build.gradle) and Spring Boot pulls in Spring MVC, Jackson (for JSON), and an embedded Tomcat. That last part is the magic — there’s no external server to install or deploy to. Your app is the server. Generate a skeleton at start.spring.io if you don’t have one (more on that in Surviving Day 1 with Spring Boot 3).
1. The main class
Nothing fancy. Just a class with main and @SpringBootApplication:
package com.coderboi.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication is three annotations in one: @Configuration, @EnableAutoConfiguration, and @ComponentScan. That last one means Spring scans this package (and below) for components — which is why your controller gets picked up automatically as long as it lives under com.coderboi.demo.
2. The controller
One annotation, one method, one endpoint. That’s it:
package com.coderboi.demo.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(@RequestParam(defaultValue = "coderboi") String name) {
return "Hey %s, the API is alive.".formatted(name);
}
}
Hit http://localhost:8080/hello and you get plain text back. Hit http://localhost:8080/hello?name=world and you get “Hey world, the API is alive.” No XML, no web.xml, no tears.
The annotations that matter
@RestController— marks the class as a web controller and tells Spring every method returns the response body directly (it’s@Controller+@ResponseBody). Without the@ResponseBodyhalf, Spring would try to resolve your return value to a view template.@GetMapping("/hello")— maps HTTPGET /helloto this method. There’s a sibling for each verb:@PostMapping,@PutMapping,@DeleteMapping,@PatchMapping.@RequestParam— binds a query-string parameter.defaultValuemakes it optional; drop that and the param becomes required (a missing one returns 400).
Returning JSON instead of text
Real APIs return JSON. Return an object (or a record) and Jackson serializes it automatically — no extra config:
public record Greeting(String message, long timestamp) {}
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(defaultValue = "coderboi") String name) {
return new Greeting("Hey %s 👋".formatted(name), System.currentTimeMillis());
}
GET /greeting?name=world now returns {"message":"Hey world 👋","timestamp":...}. To grab a value from the URL path instead of the query string, use @PathVariable:
@GetMapping("/users/{id}")
public Greeting user(@PathVariable Long id) { ... }
And to accept a JSON request body on a POST, take a @RequestBody parameter — Jackson deserializes the incoming JSON into your object.
Common gotchas
- Controller not found (404 on everything). It’s almost always component scanning — your controller lives outside the package of the
@SpringBootApplicationclass. Move it under that package tree. - Required param missing → 400. Add a
defaultValueorrequired = falseif the param is optional. - Returning a
Stringwhen you meant JSON. A rawStringreturn is sent astext/plain. Return an object/record for JSON. - Port 8080 already in use. Set
server.portinapplication.properties, or stop whatever’s squatting on the port.
FAQ
@RestController vs @Controller — which do I use?
@RestController for APIs that return data (JSON/text). @Controller is for server-rendered views (Thymeleaf, etc.) and needs @ResponseBody on methods that should return data instead of a view name.
Do I need to install Tomcat?
spring-boot-starter-web bundles an embedded Tomcat, so java -jar yourapp.jar (or running the main class) starts the server. There’s nothing separate to install or deploy to.
How do I read the request body?
@RequestBody parameter of your DTO/record type to a @PostMapping method. Jackson deserializes the JSON automatically.
How do I change the port?
server.port=9090 in application.properties (or application.yml), or pass --server.port=9090 on startup.
Key takeaway: A Spring Boot REST controller is one @RestController class with @GetMapping/@PostMapping methods; add spring-boot-starter-web, keep the controller under your main package, and return objects to get JSON for free. Five minutes, no servlet config.
Next steps: handle errors cleanly with a global exception handler, then lock it down with JWT authentication.