allthingsare๐Ÿ…ฟ๏ธ.com Books โฌ…๏ธ Back allthingsare

3.2 RESTful API Design Practice


Learning Goal:
โ€ข Learn the principles and practice of designing RESTful APIs.


Detailed Content:
โ€ข REST architecture basics: statelessness, resources, URI design
โ€ข HTTP methods (GET, POST, PUT, DELETE) and status codes
โ€ข Good vs bad REST API examples
โ€ข Designing CRUD APIs for simple modules
โ€ข Swagger Editor: write a basic API spec draft


3.2.1 REST Architecture Basics: Statelessness, Resources, URI Design

Modern web services often rely on RESTโ€”Representational State Transferโ€”as the architectural style for building clean, predictable APIs. At its core, REST is about treating data as resources and interacting with these resources using standard HTTP methods.

A RESTful API must be stateless, meaning each HTTP request from a client must contain all the information the server needs to process it. The server does not store session state between requests. This makes REST simple, scalable, and easy to cache.

Good URI design is another hallmark of a RESTful API. URIs should clearly represent resources, not actions. For example, you should design endpoints like /api/users/ to represent a collection of user resources, and /api/users/123 to represent a single user with ID 123. The URI should not contain verbs like /api/getUser or /api/updateUser.


3.2.2 HTTP Methods and Status Codes

In REST, the standard HTTP methods map naturally to CRUD operations:

  • GET retrieves a resource or collection.

  • POST creates a new resource.

  • PUT updates a whole resource.

  • DELETE removes a resource.

Status codes communicate what happened. For example:

  • 200 OK means success.

  • 201 Created means a new resource was successfully created.

  • 204 No Content means the request succeeded but there is no response body.

  • 400 Bad Request means the client sent something invalid.

  • 404 Not Found means the resource does not exist.

  • 500 Internal Server Error means something went wrong on the server.


3.2.3 Good vs Bad REST API Examples

A bad API design might look like this:

bash
POST /api/createUser GET /api/getUserById?id=123 POST /api/updateUser POST /api/deleteUser

These endpoints break REST principles because they put actions in the URI and misuse HTTP verbs.

A good RESTful design for the same functionality would look like this:

sql
POST /api/users --> create a user GET /api/users/123 --> get user with ID 123 PUT /api/users/123 --> update user with ID 123 DELETE /api/users/123 --> delete user with ID 123

Here, the URI represents resources (users), and HTTP methods express the action.


3.2.4 Designing CRUD APIs for Simple Modules: Java Code Example

Letโ€™s see how you might implement a simple User CRUD API in Java using Spring Boot.

User Entity:

java

@Entity
public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // Getters and Setters }

Repository:

java

public interface UserRepository extends JpaRepository<User, Long> {
}

Controller:

java

@RestController
@RequestMapping("/api/users") public class UserController { @Autowired private UserRepository userRepository; @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { User savedUser = userRepository.save(user); return ResponseEntity.status(HttpStatus.CREATED).body(savedUser); } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return userRepository.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).build()); } @PutMapping("/{id}") public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) { return userRepository.findById(id) .map(user -> { user.setName(userDetails.getName()); user.setEmail(userDetails.getEmail()); userRepository.save(user); return ResponseEntity.ok(user); }) .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).build()); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { return userRepository.findById(id) .map(user -> { userRepository.delete(user); return ResponseEntity.noContent().build(); }) .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).build()); } }

This simple controller demonstrates proper RESTful design:

  • URIs describe the resource: /api/users/{id}

  • HTTP methods do the work: POST creates, GET reads, PUT updates, DELETE removes.

  • Status codes correctly communicate results (201 Created, 200 OK, 404 Not Found, 204 No Content).


3.2.5 Swagger Editor: Write a Basic API Spec Draft


To make your API clear to other developers, always document it properly. Swagger (now known as OpenAPI) is a popular way to define an API spec in a human- and machine-readable format.

Hereโ€™s a simple example of how your User API might look in Swagger YAML:

yaml

openapi: 3.0.0
info: title: User API version: 1.0.0 paths: /api/users: post: summary: Create a new user requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/User' responses: '201': description: User created content: application/json: schema: $ref: '#/components/schemas/User' /api/users/{id}: get: summary: Get user by ID parameters: - name: id in: path required: true schema: type: integer responses: '200': description: User found content: application/json: schema: $ref: '#/components/schemas/User' '404': description: User not found put: summary: Update user by ID parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/User' responses: '200': description: User updated delete: summary: Delete user by ID parameters: - name: id in: path required: true schema: type: integer responses: '204': description: User deleted components: schemas: User: type: object properties: id: type: integer name: type: string email: type: string

You can paste this YAML into Swagger Editor to generate interactive API docs and even auto-generate client/server code stubs.


Wrap-Up

Designing a RESTful API well is about much more than wiring up routes. Itโ€™s about clear resource-oriented URIs, consistent HTTP methods, correct status codes, and good documentation. Combine this with clean, modular Java code and you have an API thatโ€™s easy to use, maintain, and evolve.