go
44 lines · 6 steps
Building a protected admin area in Gin
A single route group applies Basic Auth once, then hangs a dashboard and user-management handlers off it.
Explained by
highlit
1package admin
2
3import (
4 "net/http"
5
6 "github.com/gin-gonic/gin"
7)
8
9func RegisterRoutes(r *gin.Engine, deps *Dependencies) {
10 admin := r.Group("/admin")
11 admin.Use(gin.BasicAuth(gin.Accounts{
12 deps.Config.AdminUser: deps.Config.AdminPassword,
13 }))
14
15 admin.GET("/", func(c *gin.Context) {
16 c.HTML(http.StatusOK, "admin/dashboard.tmpl", gin.H{
17 "user": c.MustGet(gin.AuthUserKey).(string),
18 "stats": deps.Metrics.Snapshot(),
19 })
20 })
21
22 admin.GET("/users", func(c *gin.Context) {
23 users, err := deps.Users.List(c.Request.Context())
24 if err != nil {
25 c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "failed to load users"})
26 return
27 }
28 c.JSON(http.StatusOK, users)
29 })
30
31 admin.POST("/users/:id/ban", func(c *gin.Context) {
32 id := c.Param("id")
33 if err := deps.Users.Ban(c.Request.Context(), id); err != nil {
34 c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
35 return
36 }
37 c.JSON(http.StatusOK, gin.H{"banned": id})
38 })
39
40 admin.DELETE("/cache", func(c *gin.Context) {
41 deps.Cache.Flush()
42 c.Status(http.StatusNoContent)
43 })
44}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Grouping routes lets you attach shared middleware like auth once instead of per-handler.
- 2Passing a dependencies struct keeps handlers testable and decoupled from global state.
- 3Aborting with a status on error keeps failures explicit and stops the handler chain cleanly.
Related explainers
go
func (h *WebhookHandler) HandleBatch(c *gin.Context) { var payload BatchWebhookPayload if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
Handling batched webhooks in Gin
webhooks
signature-verification
job-queue
Intermediate
7 steps
ruby
require "net/http" require "json" require "uri" require "base64"
Paginating an HTTP API with a Ruby enumerator
pagination
http
enumerator
Intermediate
7 steps
rust
use axum::{ body::Body, http::{Method, StatusCode, Uri}, response::{IntoResponse, Response},
Nesting routers and JSON fallbacks in Axum
routing
http
json-responses
Intermediate
7 steps
go
package config import "time"
The functional options pattern in Go
functional-options
closures
immutability
Intermediate
7 steps
python
from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request from starlette.responses import JSONResponse, Response from starlette.status import HTTP_413_REQUEST_ENTITY_TOO_LARGE
Enforcing a max request body size in FastAPI
middleware
streaming
request-limits
Advanced
6 steps
php
<?php namespace App\Services;
Caching per-tenant settings in Laravel
caching
multi-tenancy
dependency-injection
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-protected-admin-area-in-gin-explained-go-cf1a/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.