Şuayb's BlogŞuayb's Blog
Home
Categories
Games
MediumAboutContact
Language
Theme
    1. Blog
    2. Programming
    3. Input Validation in REST APIs

Input Validation in REST APIs

PublishedDecember 15, 2024
UpdatedDecember 16, 2024
Reading time3 min read
JavaKotlinGoSpring BootGinValidation
XLinkedInFacebook
Input Validation in REST APIs

Loading likes...

Input validation is crucial for building secure and robust REST APIs. In this article, we will explore how to implement input validation in Spring Boot using Java, Kotlin, and Go (with Gin).


Last updatedDecember 16, 2024

Total viewsLoading hits...

Previous articleBuilding APIs with Spring for GraphQLNext articleObject-Relational Mapping
Şuayb Şimşek

Written by

Şuayb Şimşek

Backend-focused fullstack developer sharing practical notes on Spring Boot, security, microservices, and cloud-native architecture.

Expertise

  • Spring Boot
  • Go
  • Microservices
  • Next.js
  • Cloud Native

Connect

GitHubLinkedInMedium

Related posts

Object-Relational Mapping
Programming

Object-Relational Mapping

Learn how to set up an ORM-based application with Spring Boot using Java, Kotlin, and Go (Gin). Includes PostgreSQL integration and basic CRUD operations.

December 16, 20243 min read
JavaKotlinGoSpring BootGinORM
Gin - First Application
Programming

Gin - First Application

A beginner-friendly guide to creating your first Golang Gin application from scratch. Learn the basics and start your journey with Gin.

December 14, 20243 min read
GoGinBeginner Guide
Spring Boot Configuration Properties
Programming

Spring Boot Configuration Properties

Learn how to use @ConfigurationProperties for type-safe configuration, validate settings with @Validated, and manage environment-specific values with profile-specific application-{profile}.yml files.

February 4, 20263 min read
JavaKotlinSpring BootConfiguration

About

Articles on Spring Boot, microservices, security, and more.

ContactStart here

Latest posts

  • Captain Tsubasa 2: World Fighters
  • Captain Tsubasa: Rise of New Champions
  • Spring Boot Configuration Properties
  • Spring Boot GraphQL JWE Authentication
  • Spring Boot JWE Authentication with JPA

Top topics

JavaKotlinSpring BootJWEJWTMicroservice

Subscribe

Get practical backend + fullstack notes when new articles are published.

Social

© 2024-2026 Şuayb's Blog. All rights reserved.

🌟 Why Validate Input?

Validation ensures the data sent to your API adheres to expected formats and prevents potential vulnerabilities like SQL Injection, XSS, and bad data entries.


📋 Prerequisites

Before implementing validation, make sure you have:

  • Java 17+ for Spring Boot examples
  • Go 1.21+ for Gin examples
  • A running Spring Boot or Gin starter project
  • Basic familiarity with DTOs, JSON payloads, and HTTP status codes

🧪 Step 1: Add Validation Dependencies

For Spring Boot projects, include the following dependencies:

  • Maven:
XMLpom.xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • Gradle:
GROOVYbuild.gradle
implementation 'org.springframework.boot:spring-boot-starter-validation'

For Go projects with Gin, use the following:

BASH
# Install the Gin framework
go get -u github.com/gin-gonic/gin

# Install the validator package
go get -u github.com/go-playground/validator/v10

🧪 Step 2: Define a DTO with Validation Rules

Use annotations to define validation constraints on fields. Examples include @NotNull, @Size, and @Pattern.


🧪 Step 3: Create a Controller with Validation

Integrate validation into your REST endpoints.


🧪 Step 4: Handle Validation Errors

Customize error handling to return user-friendly responses.


main.go Example

Here is an example of the main.go file for setting up a Gin application:

GOmain.go
package main

import (
	"controller"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.POST("/api/todos", controller.CreateTodoHandler)

	r.Run() // Start the server on http://localhost:8080
}

▶️ Step 5: Run the Application

To run the application:

Spring Boot (Java/Kotlin): Run the Spring Boot application from your IDE or terminal:

BASH
./mvnw spring-boot:run # For Maven projects
./gradlew bootRun       # For Gradle projects

Access the API at http://localhost:8080/api/todos.

Gin (Go)

Run the Go application:

BASH
go run main.go

Access the API at http://localhost:8080/api/todos.

🧪 Testing with cURL

Here are some example cURL commands to test the API:

  • POST a new Todo:
BASH
curl -X POST http://localhost:8080/api/todos \
-H "Content-Type: application/json" \
-d '{"title": "New Task", "completed": false}'
  • GET all Todos:
BASH
curl -X GET http://localhost:8080/api/todos
  • Handle Validation Errors:

Send an invalid request:

BASH
curl -X POST http://localhost:8080/api/todos \
-H "Content-Type: application/json" \
-d '{"title": ""}'

🏁 Conclusion

You now have a practical Input Validation in REST APIs implementation with a clear, production-friendly Spring Boot structure. As a next step, adapt configuration and tests to your own domain, then validate behavior under realistic traffic and failure scenarios.

JAVATodoRequest.java
package com.example.demo.dto;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class TodoRequest {

    @NotNull(message = "Title is required")
    @Size(min = 3, max = 50, message = "Title must be between 3 and 50 characters")
    private String title;

    private boolean completed;
}
KOTLINTodoRequest.kt
package com.example.demo.dto

import jakarta.validation.constraints.NotNull
import jakarta.validation.constraints.Size

data class TodoRequest(
    @field:NotNull(message = "Title is required")
    @field:Size(min = 3, max = 50, message = "Title must be between 3 and 50 characters")
    val title: String?,

    val completed: Boolean = false
)
GOapp.go
package dto

import (
    "github.com/go-playground/validator/v10"
)

type TodoRequest struct {
    Title     string `validate:"required,min=3,max=50"`
    Completed bool   `validate:""`
}

var validate = validator.New()

func ValidateTodoRequest(todo TodoRequest) error {
    return validate.Struct(todo)
}
JAVATodoController.java
package com.example.demo.controller;

import com.example.demo.dto.TodoRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/todos")
public class TodoController {

    @PostMapping
    public String createTodo(@Validated @RequestBody TodoRequest request) {
        return "Todo created: " + request.getTitle();
    }
}
KOTLINTodoController.kt
package com.example.demo.controller

import com.example.demo.dto.TodoRequest
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/todos")
class TodoController {

    @PostMapping
    fun createTodo(@Validated @RequestBody request: TodoRequest): String {
        return "Todo created: ${request.title}"
    }
}
GOapp.go
package controller

import (
    "dto"
    "github.com/gin-gonic/gin"
    "net/http"
)

func CreateTodoHandler(c *gin.Context) {
    var todo dto.TodoRequest

    if err := c.ShouldBindJSON(&todo); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    if err := dto.ValidateTodoRequest(todo); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "Todo created", "title": todo.Title})
}
JAVAGlobalExceptionHandler.java
package com.example.demo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.MethodArgumentNotValidException;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> errors.put(error.getField(), error.getDefaultMessage()));
        return errors;
    }
}
KOTLINGlobalExceptionHandler.kt
package com.example.demo.exception

import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.bind.MethodArgumentNotValidException

@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException::class)
    fun handleValidationExceptions(ex: MethodArgumentNotValidException): Map<String, String> {
        return ex.bindingResult.fieldErrors.associate { it.field to it.defaultMessage.orEmpty() }
    }
}
GOapp.go
package middleware

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func ErrorHandler() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Next()

        if len(c.Errors) > 0 {
            c.JSON(http.StatusBadRequest, gin.H{"errors": c.Errors.JSON()})
        }
    }
}