Skip to content
Back to skills

Gin

ASecurity

Gin is a Go web framework with a Martini-like API and a zero-allocation router. Use it to build HTTP APIs that need routing, middleware, request binding/validation, JSON responses, and graceful shutdown with low per-request overhead. Use when a user asks to scaffold a Go HTTP API, add route groups or middleware, validate request bodies, or shut a Go server down cleanly.

  • 142 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 29, 2026
developmentgobashkubernetesgitapidatabaseperformance

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill gin --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gin?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gin
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-gin/badge)](https://www.skillsdirectory.com/skills/terminalskills-gin)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gin
description: >-
  Gin is a Go web framework with a Martini-like API and a zero-allocation
  router. Use it to build HTTP APIs that need routing, middleware, request
  binding/validation, JSON responses, and graceful shutdown with low
  per-request overhead. Use when a user asks to scaffold a Go HTTP API,
  add route groups or middleware, validate request bodies, or shut a Go
  server down cleanly.
license: Apache-2.0
compatibility: "Go 1.21+ (the current gin release's go.mod requires Go 1.26)"
metadata:
  author: terminal-skills
  version: "1.1.0"
  category: development
  tags:
    - go
    - web-framework
    - http
    - rest
    - middleware
  repository: https://github.com/gin-gonic/gin
---

# Gin — High-Performance Go Web Framework

## Overview

Gin is a minimal, fast HTTP web framework for Go built on `net/http` with a radix-tree router (originally based on httprouter). It provides routing, route groups, middleware chaining, request binding/validation via `go-playground/validator`, and JSON/XML/YAML rendering helpers. It is unopinionated about project layout and data access — you wire in your own database and auth logic.

## Instructions

### Install

```bash
go get github.com/gin-gonic/gin
```

This adds `github.com/gin-gonic/gin` to `go.mod`. Gin's own `go.mod` currently requires Go 1.26 to build from source; a project that only imports Gin as a dependency needs a Go toolchain at least that new to resolve the module.

### Build routes and middleware

- `gin.Default()` returns an engine with the `Logger` and `Recovery` middleware attached; `gin.New()` returns a bare engine.
- `r.Group("/api")` creates a route group; call `.Use(middleware)` on the group to scope middleware to it.
- Middleware is a `func(*gin.Context)`; call `c.Next()` to continue the chain or `c.Abort()`/`c.AbortWithStatusJSON(...)` to stop it.
- `c.ShouldBindJSON(&v)` parses and validates the request body against struct `binding` tags, returning an error instead of aborting — check it yourself.
- Set `GIN_MODE=release` (or `gin.SetMode(gin.ReleaseMode)`) in production; debug mode logs every route registration and is slower.

### Shut down without dropping in-flight requests

Gin's own `r.Run(":8080")` blocks forever and has no shutdown hook, so production services run `http.Server{Handler: r}` directly and call `Shutdown(ctx)` on a signal, as in Example 2 below.

## Examples

### Example 1: "Add a versioned `/api/v1` group with JWT auth and request validation"

```go
package main

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

type CreateOrderRequest struct {
	ProductSKU string `json:"productSku" binding:"required"`
	Quantity   int    `json:"quantity" binding:"required,min=1"`
}

func main() {
	r := gin.Default() // Logger + Recovery middleware

	v1 := r.Group("/api/v1")
	v1.Use(authMiddleware())
	{
		v1.GET("/orders", listOrders)
		v1.POST("/orders", createOrder)
		v1.GET("/orders/:id", getOrder)
	}

	r.Run(":8080") // fine for local dev; see Example 2 for production
}

func listOrders(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))

	orders, total := store.FindOrders(page, limit)
	c.JSON(http.StatusOK, gin.H{"data": orders, "total": total, "page": page})
}

func createOrder(c *gin.Context) {
	var req CreateOrderRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	order, err := store.CreateOrder(req.ProductSKU, req.Quantity)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "could not create order"})
		return
	}
	c.JSON(http.StatusCreated, order)
}

func getOrder(c *gin.Context) {
	order, err := store.FindOrder(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "order not found"})
		return
	}
	c.JSON(http.StatusOK, order)
}

func authMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
			return
		}
		user, err := validateJWT(token)
		if err != nil {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
			return
		}
		c.Set("user", user)
		c.Next()
	}
}
```

Result: `POST /api/v1/orders` without a token returns `401 {"error":"missing token"}`; with a valid token and a body missing `quantity` it returns `400` naming the failed validation; a valid request returns `201` with the created order.

### Example 2: "Make the server shut down gracefully on SIGTERM so Kubernetes rollouts don't drop requests"

```go
package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/healthz", func(c *gin.Context) { c.Status(http.StatusOK) })

	srv := &http.Server{Addr: ":8080", Handler: r}
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %v", err)
		}
	}()

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Printf("forced shutdown: %v", err)
	}
}
```

Result: on `SIGTERM`, the process stops accepting new connections and waits up to 5 seconds for in-flight requests to finish before exiting, instead of killing them mid-response.

## Guidelines

- Prefer `ShouldBindJSON`/`ShouldBindQuery` over the panicking `BindJSON`/`BindQuery` variants — the `Should*` forms return an error you handle, while the non-`Should` forms abort the request with a 400 for you, which is easy to forget and double-handle.
- `gin.H{}` is a `map[string]any` alias — fine for ad-hoc responses, but use typed structs for anything with a documented response shape (OpenAPI, client codegen).
- Middleware runs in registration order on the way in and reverse order after `c.Next()` returns, so put logging/recovery first and auth after CORS.
- Gin does not include a built-in rate limiter, CORS handler, or JWT parser; pull in a dedicated middleware package (or write one) rather than reimplementing token parsing inline.
- Debug mode (the default) logs every registered route and warns on stdout; always set `GIN_MODE=release` for production builds.
- `r.Run()` has no graceful shutdown; use it only for local development, and switch to an explicit `http.Server` plus `Shutdown(ctx)` for anything deployed.

Files in this skill

  • SKILL.md4.6 KB
  • _scores.json1.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.