Ensures user input is valid.

api-go
	|
	|-------> internal 
								|------> dto
								|					|-----> websites.go
								|
								|------> handlers
								|					|-----> websites.go
								|
								|------> routes
													|-----> websites.go

Step 1 : Define DTO package

DTO is used for moving data between client <-> server

Data Transfer Object ( DTO ) : struct whose job is to describe data coming IN or going OUT of your system

DTO defines:

  1. shape of request body
  2. shape of response body
  3. validation rules
  4. serialisation ( json tags )

internal/dto/websites.go

package dto

type CreateWebsiteRequest struct {
	URL string `json:"url" binding:"required,url,max=2048"`
}

Step 2 : Modify CreateWebsite handler to add logic for validating user’s input

package handlers

import (
	"net/http"

	"github.com/RitikaxG/runState/apps/api-go/internal/dto"
	"github.com/gin-gonic/gin"
)

// Handler Fn
func GetWebsites(c *gin.Context) { // gin.Context : single HTTP request + response ( lives only during that request )
	c.JSON(http.StatusOK, gin.H{
		"message": "List all websites",
	})
}

func CreateWebsite(c *gin.Context) {
	var body dto.CreateWebsiteRequest // Declaring a Go struct that defines what JSON you expect

	// & body : pointer to where body lives in memory
	// &body is passed because Gin must modify body, and Go can only modify a variable if you give it its memory address.
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"message": "invalid request body",
			"error":   err.Error(),
		})
		return // Prevents handler from continuing
	}

	c.JSON(http.StatusCreated, gin.H{
		"message": "Website successfully created",
		"url":     body.URL, // Uses parsed data
	})
}

Go automatically :

  1. Parses JSON
  2. runs validation tags (validate:"")..

if err := c.ShouldBindJSON(&body); err != nil What happens here internally ?

Gin:

  1. Reads request body
  2. Parses JSON
  3. Matches JSON fields to struct tags
  4. Validates rules (binding:"required")
  5. Populates body

If anything fails, err != nil. Examples of failure:

  1. Invalid JSON
  2. Missing required fields
  3. Wrong data types
  4. Validation errors returns BadRequest status code

internal/handler/websites.go

Step 3 : Use the handler in websites route

internal/routes/websites.go

func RegisterWebsitesRouter(r *gin.RouterGroup) { // gin.RouterGroup : organises the routes
	websites := r.Group("/websites")
	websites.GET("/", handlers.GetWebsites)
	websites.POST("/", handlers.CreateWebsite)
}

Notes :

What actually happens inside Gin

When you call: