package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
r.Run(":8080")
}
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
ID int `json:"id"`
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
var users []User
var nextID = 1
func main() {
r := gin.Default()
// GET all users
r.GET("/users", getUsers)
// POST new user
r.POST("/users", createUser)
r.Run(":8080")
}
func getUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"data": users,
"count": len(users),
})
}
func createUser(c *gin.Context) {
var newUser User
if err := c.ShouldBindJSON(&newUser); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
newUser.ID = nextID
nextID++
users = append(users, newUser)
c.JSON(http.StatusCreated, gin.H{
"message": "User created successfully",
"data": newUser,
})
}type RegisterRequest struct {
Username string `json:"username" binding:"required,min=3,max=20"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=8"`
Age int `json:"age" binding:"required,min=18,max=100"`
}
func registerUser(c *gin.Context) {
var req RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid input",
"details": err.Error(),
})
return
}
// Process valid data
c.JSON(http.StatusOK, gin.H{
"message": "User registered successfully",
"username": req.Username,
})
}
type User struct {
Username string `json:"username" binding:"required,min=3,max=20"`
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"required,gte=18,lte=100"`
Password string `json:"password" binding:"required,min=8"`
}
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
var validationErrors []string
if ve, ok := err.(validator.ValidationErrors); ok {
for _, e := range ve {
switch e.Tag() {
case "required":
validationErrors = append(validationErrors,
fmt.Sprintf("%s is required", e.Field()))
case "email":
validationErrors = append(validationErrors,
"Invalid email format")
case "min":
validationErrors = append(validationErrors,
fmt.Sprintf("%s must be at least %s characters",
e.Field(), e.Param()))
}
}
}
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Validation failed",
"errors": validationErrors,
})
return
}
c.JSON(http.StatusCreated, gin.H{
"status": "success",
"message": "User created successfully",
"data": user,
})
}package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
type APIResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
Errors []string `json:"errors,omitempty"`
Meta *Meta `json:"meta,omitempty"`
Version string `json:"version"`
}
type Meta struct {
Page int `json:"page"`
Limit int `json:"limit"`
Total int `json:"total"`
TotalPages int `json:"total_pages"`
}
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var users = []User{
{ID: 1, Name: "John Doe", Email: "john@example.com"},
{ID: 2, Name: "Jane Smith", Email: "jane@example.com"},
}
func successResponse(c *gin.Context, message string, data interface{}, meta *Meta) {
response := APIResponse{
Status: "success",
Message: message,
Data: data,
Meta: meta,
Version: "v1",
}
c.JSON(http.StatusOK, response)
}
func errorResponse(c *gin.Context, statusCode int, message string, errors []string) {
response := APIResponse{
Status: "error",
Message: message,
Errors: errors,
Version: "v1",
}
c.JSON(statusCode, response)
}
func getUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
if page < 1 {
page = 1
}
if limit < 1 || limit > 100 {
limit = 10
}
start := (page - 1) * limit
end := start + limit
if start >= len(users) {
successResponse(c, "Users retrieved successfully", []User{}, &Meta{
Page: page,
Limit: limit,
Total: len(users),
TotalPages: (len(users) + limit - 1) / limit,
})
return
}
if end > len(users) {
end = len(users)
}
paginatedUsers := users[start:end]
meta := &Meta{
Page: page,
Limit: limit,
Total: len(users),
TotalPages: (len(users) + limit - 1) / limit,
}
successResponse(c, "Users retrieved successfully", paginatedUsers, meta)
}
func getUserByID(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
errorResponse(c, http.StatusBadRequest, "Invalid user ID", []string{"ID must be a valid number"})
return
}
for _, user := range users {
if user.ID == id {
successResponse(c, "User found", user, nil)
return
}
}
errorResponse(c, http.StatusNotFound, "User not found", []string{"User with specified ID does not exist"})
}
func main() {
r := gin.Default()
// API versioning
v1 := r.Group("/api/v1")
{
v1.GET("/users", getUsers)
v1.GET("/users/:id", getUserByID)
}
r.Run(":8080")
}func BasicAuth() gin.HandlerFunc {
return gin.BasicAuth(gin.Accounts{
"admin": "secret123",
"user": "password",
})
}
func setupRoutes() *gin.Engine {
r := gin.Default()
authorized := r.Group("/admin", BasicAuth())
authorized.GET("/dashboard", getDashboard)
return r
}
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)import "github.com/golang-jwt/jwt/v4"
func GenerateToken(userID uint) (string, error) {
claims := jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte("secret-key"))
}
func ValidateToken(tokenString string) (*jwt.Token, error) {
return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte("secret-key"), nil
})
}
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
)
type User struct {
ID uint `json:"id"`
Name string `json:"name"`
Role string `json:"role"`
}
type Claims struct {
UserID uint `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
var users = map[uint]User{
1: {ID: 1, Name: "Admin", Role: "admin"},
2: {ID: 2, Name: "User", Role: "user"},
}
func RequireRole(allowedRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(401, gin.H{"error": "Token required"})
c.Abort()
return
}
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return []byte("secret-key"), nil
})
if err != nil || !token.Valid {
c.JSON(401, gin.H{"error": "Invalid token"})
c.Abort()
return
}
for _, role := range allowedRoles {
if claims.Role == role {
c.Set("user_id", claims.UserID)
c.Set("role", claims.Role)
c.Next()
return
}
}
c.JSON(403, gin.H{"error": "Insufficient permissions"})
c.Abort()
}
}
func main() {
r := gin.Default()
// Public endpoint
r.GET("/public", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Public access"})
})
// Admin only
r.GET("/admin", RequireRole("admin"), func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Admin area"})
})
// Admin and user
r.GET("/dashboard", RequireRole("admin", "user"), func(c *gin.Context) {
role := c.GetString("role")
c.JSON(200, gin.H{
"message": "Dashboard access",
"role": role,
})
})
r.Run(":8080")
}
// SQL Injection Vulnerability
func getUserByID(id string) User {
query := "SELECT * FROM users WHERE id = " + id
// DANGEROUS: Direct string concatenation
rows, _ := db.Query(query)
// Attacker input: "1 OR 1=1"
}
// XSS Vulnerability
func displayComment(comment string) {
// DANGEROUS: Unescaped output
html := "<div>" + comment + "</div>"
// Attacker input: "<script>alert('XSS')</script>"
}
// CSRF Vulnerability
func deleteUser(c *gin.Context) {
// DANGEROUS: No CSRF protection
userID := c.Param("id")
db.Delete(&User{}, userID)
}// SQL Injection Prevention dengan GORM
func getUserByID(id uint) (User, error) {
var user User
// SAFE: GORM menggunakan prepared statements
result := db.First(&user, id)
return user, result.Error
}
// XSS Prevention dengan HTML Escaping
func displayComment(c *gin.Context) {
comment := c.PostForm("comment")
// SAFE: Gin secara otomatis escape HTML
c.HTML(200, "comment.html", gin.H{
"comment": comment, // Automatically escaped
})
}
// CSRF Prevention dengan Middleware
func setupCSRF() gin.HandlerFunc {
return csrf.Middleware(csrf.Options{
Secret: "your-secret-key",
ErrorFunc: func(c *gin.Context) {
c.JSON(403, gin.H{"error": "CSRF token invalid"})
},
})
}
func main() {
r := gin.Default()
r.Use(setupCSRF()) // Apply CSRF protection
r.POST("/delete/:id", deleteUser)
}type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
// Relationships
Posts []Post `gorm:"foreignKey:UserID"`
}
type Post struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"size:200;not null"`
UserID uint
User User `gorm:"references:ID"`
}
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func InitDB() (*gorm.DB, error) {
dsn := "host=localhost user=postgres password=secret dbname=myapp port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
return nil, err
}
// Auto migrate
db.AutoMigrate(&User{}, &Product{})
return db, nil
}
type UserRepository struct {
db *gorm.DB
}
func (r *UserRepository) Create(user *User) error {
return r.db.Create(user).Error
}
func (r *UserRepository) GetByID(id uint) (*User, error) {
var user User
err := r.db.Preload("Posts").First(&user, id).Error
return &user, err
}
func (r *UserRepository) Update(user *User) error {
return r.db.Save(user).Error
}
func (r *UserRepository) Delete(id uint) error {
return r.db.Delete(&User{}, id).Error
}
controllers/
├── user_controller.go
├── product_controller.go
└── auth_controller.gomodels/
├── user.go
├── product.go
└── database.goroutes/
├── api.go
└── middleware.go
main.go
go.modpackage main
import (
"fmt"
"time"
)
func sayHello(name string) {
for i := 0; i < 3; i++ {
fmt.Printf("Hello %s! %d\n", name, i)
time.Sleep(100 * time.Millisecond)
}
}
func main() {
// Sequential execution
sayHello("Alice")
// Concurrent execution with goroutines
go sayHello("Bob")
go sayHello("Charlie")
// Wait for goroutines to complete
time.Sleep(500 * time.Millisecond)
fmt.Println("Main function completed")
}// Membuat channel
ch := make(chan string)
// Mengirim data
go func() {
ch <- "Hello from goroutine"
}()
// Menerima data
message := <-ch
fmt.Println(message)
// Buffered channel
buffered := make(chan int, 3)
buffered <- 1
buffered <- 2package main
import (
"fmt"
"time"
)
// Simulasi API request processing
func processAPIRequest(id int, ch chan string) {
// Simulate API processing time
time.Sleep(200 * time.Millisecond)
result := fmt.Sprintf("API Request %d processed", id)
ch <- result // Send ke channel (blocking)
}
func main() {
// Unbuffered channel
resultChan := make(chan string)
// Launch goroutines untuk process requests
for i := 1; i <= 3; i++ {
go processAPIRequest(i, resultChan)
}
// Receive results dari channel
for i := 1; i <= 3; i++ {
result := <-resultChan // Receive dari channel (blocking)
fmt.Println(result)
}
fmt.Println("All API requests completed")
}func ProcessOrdersConcurrently(orders []Order) error {
const maxWorkers = 10
orderChan := make(chan Order, len(orders))
errorChan := make(chan error, len(orders))
// Start workers
for i := 0; i < maxWorkers; i++ {
go func() {
for order := range orderChan {
if err := processOrder(order); err != nil {
errorChan <- err
} else {
errorChan <- nil
}
}
}()
}
// Send orders to channel
for _, order := range orders {
orderChan <- order
}
close(orderChan)
// Collect results
for i := 0; i < len(orders); i++ {
if err := <-errorChan; err != nil {
return err
}
}
return nil
}
type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
func (c *SafeCounter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}
// Usage in API handler
func incrementHandler(counter *SafeCounter) gin.HandlerFunc {
return func(c *gin.Context) {
counter.Increment()
c.JSON(200, gin.H{"count": counter.Value()})
}
}
func TestCreateUser(t *testing.T) {
gin.SetMode(gin.TestMode)
tests := []struct {
name string
payload string
expected int
}{
{"Valid user", `{"name":"John","email":"john@example.com"}`, 201},
{"Invalid email", `{"name":"John","email":"invalid"}`, 400},
{"Missing name", `{"email":"john@example.com"}`, 400},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/users", strings.NewReader(tt.payload))
req.Header.Set("Content-Type", "application/json")
router := setupRouter()
router.ServeHTTP(w, req)
assert.Equal(t, tt.expected, w.Code)
})
}
}
# Multi-stage Dockerfile for Go
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]