Introduction
A well-designed REST API URL structure is crucial for building scalable, readable, and maintainable APIs. In this blog, we will break down the components of a REST API URL, discuss best practices, and implement them in Spring Boot with a complete example.
1. General REST API URL Structure
A standard REST API URL follows this pattern:
https://api.example.com/{version}/{resource}/{resource-id}/{sub-resource}Breakdown:
- 
https://→ Secure protocol (HTTPS is preferred)
- 
api.example.com→ Domain name or API host
- 
{version}→ API versioning (e.g.,v1,v2)
- 
{resource}→ Plural noun representing the resource (e.g.,users,products)
- 
{resource-id}→ Unique identifier for a resource (e.g.,users/123)
- 
{sub-resource}→ Nested resource related to the main resource (e.g.,users/123/orders)
2. Components of REST API URL
A. Versioning in REST API
Versioning ensures backward compatibility and can be implemented in different ways:
- URL Path Versioning (Recommended)
https://api.example.com/v1/users- Header Versioning
GET /users
Accept: application/vnd.example.v1+json- Query Parameter Versioning
GET /users?version=1B. Resource Naming (Use Plural Nouns)
Always use plural nouns for resources:
GET /v1/users      → Get all users  
GET /v1/users/123  → Get user with ID 123  
POST /v1/users     → Create a new user  
PUT /v1/users/123  → Update user 123  
DELETE /v1/users/123 → Delete user 123C. Sub-Resources for Relationships
Use sub-resources to represent relationships:
GET /v1/users/123/orders → Get orders of user 123  
GET /v1/users/123/orders/456 → Get order 456 of user 123D. Query Parameters for Filtering, Sorting, and Pagination
Filtering:
GET /v1/products?category=electronics&brand=appleSorting:
GET /v1/products?sort=price_ascPagination:
GET /v1/products?page=2&limit=20Offset-based Pagination:
GET /v1/products?offset=40&limit=20E. Actions that Don’t Fit CRUD (Use Verbs as Subpaths)
For actions beyond CRUD, use verbs:
POST /v1/users/123/activate → Activate user 123  
POST /v1/orders/789/cancel → Cancel order 789F. Status and Error Handling
Use appropriate HTTP status codes:
- 
200 OK→ Successful request
- 
201 Created→ Resource created
- 
400 Bad Request→ Client error
- 
404 Not Found→ Resource not found
- 
500 Internal Server Error→ Server issue
3. Best Practices for REST API URL Design
✅ Use nouns for resources (/users instead of /getUsers)
✅ Use hyphens (-) instead of underscores (_) in URLs (/user-profiles not /user_profiles)
✅ Use lowercase letters (/orders instead of /Orders)
✅ Avoid file extensions (/users.json is unnecessary)
✅ Keep URLs short and intuitive
4. Spring Boot Implementation
Let's implement these best practices in a Spring Boot REST API for managing users and orders.
A. User Controller with Versioning, Pagination, Filtering, Offset-based Pagination, and Sorting
@RestController
@RequestMapping("/v1/users")
public class UserController {
    @Autowired
    private UserRepository userRepository;
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers(
            @RequestParam(required = false) String name,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir,
            @RequestParam(required = false) Integer offset) {
        Sort sort = sortDir.equalsIgnoreCase("desc") ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
        Pageable pageable = offset != null ? PageRequest.of(offset / size, size, sort) : PageRequest.of(page, size, sort);
        Page<User> users;
        if (name != null) {
            users = userRepository.findByNameContaining(name, pageable);
        } else {
            users = userRepository.findAll(pageable);
        }
        return ResponseEntity.ok(users.getContent());
    }
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userRepository.findById(id)
                .map(ResponseEntity::ok)
                .orElseGet(() -> ResponseEntity.notFound().build());
    }
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        return ResponseEntity.status(HttpStatus.CREATED).body(userRepository.save(user));
    }
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User updatedUser) {
        return userRepository.findById(id).map(user -> {
            user.setName(updatedUser.getName());
            user.setEmail(updatedUser.getEmail());
            return ResponseEntity.ok(userRepository.save(user));
        }).orElseGet(() -> ResponseEntity.notFound().build());
    }
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userRepository.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}Conclusion
Designing a RESTful API URL properly improves usability, scalability, and maintainability. By following best practices and implementing them in Spring Boot, you can build high-quality, developer-friendly APIs with versioning, pagination, offset-based pagination, sorting, and filtering.
Would you like to extend this with authentication or advanced query capabilities? Let me know in the comments! 🚀