feat: add docs

This commit is contained in:
2025-11-02 22:29:24 -03:00
parent 3b1b05d5a6
commit 92f13fba22
7 changed files with 1070 additions and 8 deletions

40
cmd/server/main.go Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"log"
"net/http"
_ "gitea.gabilandia.com/gabdlr/agenda-web-go/docs"
"gitea.gabilandia.com/gabdlr/agenda-web-go/internal/database"
"gitea.gabilandia.com/gabdlr/agenda-web-go/internal/handler"
"gitea.gabilandia.com/gabdlr/agenda-web-go/internal/repository"
httpSwagger "github.com/swaggo/http-swagger"
)
// @title Contacts API
// @version 1.0
// @description A simple Contacts CRUD API
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.email support@yourapp.com
// @license.name MIT
// @license.url https://opensource.org/licenses/MIT
// @host localhost:8080
// @BasePath /
func main() {
err := database.InitDB(database.Conn_string)
defer database.CloseDB()
if err != nil {
log.Fatal("Database connection failed:", err)
}
mux := http.NewServeMux()
contactRepo := repository.NewContactRepository(database.DB)
handler.HandleContacts(mux, contactRepo)
handler.HandlHealthChecks(mux)
mux.HandleFunc("/swagger/", httpSwagger.WrapHandler)
log.Fatal(http.ListenAndServe(":8080", mux))
}

375
docs/docs.go Normal file
View File

@@ -0,0 +1,375 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs
import "github.com/swaggo/swag"
const docTemplate = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{escape .Description}}",
"title": "{{.Title}}",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "API Support",
"email": "support@yourapp.com"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/contacts": {
"get": {
"description": "Get a list of all contacts",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get all contacts",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Contact"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"post": {
"description": "Create a new contact with the provided data",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Create a new contact",
"parameters": [
{
"description": "Contact object",
"name": "contact",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Contact"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.Contact"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
}
},
"/contacts/{id}": {
"get": {
"description": "Get a single contact by its ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get a contact by ID",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.Contact"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"put": {
"description": "Update an existing contact by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Update a contact",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Contact object",
"name": "contact",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Contact"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"delete": {
"description": "Delete a contact by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Delete a contact",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
}
}
},
"definitions": {
"handler.APIError": {
"type": "object",
"properties": {
"code": {
"description": "Error code",
"type": "integer"
},
"details": {
"description": "Additional error details",
"type": "string"
},
"message": {
"description": "Human-readable error message",
"type": "string"
}
}
},
"handler.APIResponse": {
"type": "object",
"properties": {
"data": {
"description": "The response data"
},
"errors": {
"description": "List of errors if any occurred",
"type": "array",
"items": {
"$ref": "#/definitions/handler.APIError"
}
},
"message": {
"description": "Optional message",
"type": "string"
},
"success": {
"description": "Indicates if the request was successful",
"type": "boolean"
}
}
},
"models.Contact": {
"type": "object",
"properties": {
"company": {
"description": "Company the contact works for",
"type": "string"
},
"id": {
"description": "ID is the unique identifier for the contact",
"type": "integer"
},
"name": {
"description": "Name of the contact",
"type": "string"
},
"phone": {
"description": "Phone number in international format",
"type": "string"
}
}
}
}
}`
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "localhost:8080",
BasePath: "/",
Schemes: []string{},
Title: "Contacts API",
Description: "A simple Contacts CRUD API",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

351
docs/swagger.json Normal file
View File

@@ -0,0 +1,351 @@
{
"swagger": "2.0",
"info": {
"description": "A simple Contacts CRUD API",
"title": "Contacts API",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "API Support",
"email": "support@yourapp.com"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "1.0"
},
"host": "localhost:8080",
"basePath": "/",
"paths": {
"/contacts": {
"get": {
"description": "Get a list of all contacts",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get all contacts",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Contact"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"post": {
"description": "Create a new contact with the provided data",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Create a new contact",
"parameters": [
{
"description": "Contact object",
"name": "contact",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Contact"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.Contact"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
}
},
"/contacts/{id}": {
"get": {
"description": "Get a single contact by its ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get a contact by ID",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.Contact"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"put": {
"description": "Update an existing contact by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Update a contact",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Contact object",
"name": "contact",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.Contact"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
},
"delete": {
"description": "Delete a contact by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Delete a contact",
"parameters": [
{
"type": "integer",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/handler.APIResponse"
}
}
}
}
}
},
"definitions": {
"handler.APIError": {
"type": "object",
"properties": {
"code": {
"description": "Error code",
"type": "integer"
},
"details": {
"description": "Additional error details",
"type": "string"
},
"message": {
"description": "Human-readable error message",
"type": "string"
}
}
},
"handler.APIResponse": {
"type": "object",
"properties": {
"data": {
"description": "The response data"
},
"errors": {
"description": "List of errors if any occurred",
"type": "array",
"items": {
"$ref": "#/definitions/handler.APIError"
}
},
"message": {
"description": "Optional message",
"type": "string"
},
"success": {
"description": "Indicates if the request was successful",
"type": "boolean"
}
}
},
"models.Contact": {
"type": "object",
"properties": {
"company": {
"description": "Company the contact works for",
"type": "string"
},
"id": {
"description": "ID is the unique identifier for the contact",
"type": "integer"
},
"name": {
"description": "Name of the contact",
"type": "string"
},
"phone": {
"description": "Phone number in international format",
"type": "string"
}
}
}
}
}

227
docs/swagger.yaml Normal file
View File

@@ -0,0 +1,227 @@
basePath: /
definitions:
handler.APIError:
properties:
code:
description: Error code
type: integer
details:
description: Additional error details
type: string
message:
description: Human-readable error message
type: string
type: object
handler.APIResponse:
properties:
data:
description: The response data
errors:
description: List of errors if any occurred
items:
$ref: '#/definitions/handler.APIError'
type: array
message:
description: Optional message
type: string
success:
description: Indicates if the request was successful
type: boolean
type: object
models.Contact:
properties:
company:
description: Company the contact works for
type: string
id:
description: ID is the unique identifier for the contact
type: integer
name:
description: Name of the contact
type: string
phone:
description: Phone number in international format
type: string
type: object
host: localhost:8080
info:
contact:
email: support@yourapp.com
name: API Support
description: A simple Contacts CRUD API
license:
name: MIT
url: https://opensource.org/licenses/MIT
termsOfService: http://swagger.io/terms/
title: Contacts API
version: "1.0"
paths:
/contacts:
get:
consumes:
- application/json
description: Get a list of all contacts
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/handler.APIResponse'
- properties:
data:
items:
$ref: '#/definitions/models.Contact'
type: array
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handler.APIResponse'
summary: Get all contacts
tags:
- contacts
post:
consumes:
- application/json
description: Create a new contact with the provided data
parameters:
- description: Contact object
in: body
name: contact
required: true
schema:
$ref: '#/definitions/models.Contact'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/handler.APIResponse'
- properties:
data:
$ref: '#/definitions/models.Contact'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handler.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handler.APIResponse'
summary: Create a new contact
tags:
- contacts
/contacts/{id}:
delete:
consumes:
- application/json
description: Delete a contact by ID
parameters:
- description: Contact ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handler.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handler.APIResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/handler.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handler.APIResponse'
summary: Delete a contact
tags:
- contacts
get:
consumes:
- application/json
description: Get a single contact by its ID
parameters:
- description: Contact ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/handler.APIResponse'
- properties:
data:
$ref: '#/definitions/models.Contact'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handler.APIResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/handler.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handler.APIResponse'
summary: Get a contact by ID
tags:
- contacts
put:
consumes:
- application/json
description: Update an existing contact by ID
parameters:
- description: Contact ID
in: path
name: id
required: true
type: integer
- description: Contact object
in: body
name: contact
required: true
schema:
$ref: '#/definitions/models.Contact'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handler.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handler.APIResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/handler.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handler.APIResponse'
summary: Update a contact
tags:
- contacts
swagger: "2.0"

View File

@@ -28,6 +28,15 @@ func HandleContacts(mux *http.ServeMux, repo repository.Repository[models.Contac
NewBaseHandler(mux, routes) NewBaseHandler(mux, routes)
} }
// GetAll godoc
// @Summary Get all contacts
// @Description Get a list of all contacts
// @Tags contacts
// @Accept json
// @Produce json
// @Success 200 {object} APIResponse{data=[]models.Contact}
// @Failure 500 {object} APIResponse
// @Router /contacts [get]
func (h *ContactHandler) getAll(w http.ResponseWriter, r *http.Request) { func (h *ContactHandler) getAll(w http.ResponseWriter, r *http.Request) {
contacts, err := h.repository.GetAll() contacts, err := h.repository.GetAll()
if err != nil { if err != nil {
@@ -37,6 +46,18 @@ func (h *ContactHandler) getAll(w http.ResponseWriter, r *http.Request) {
JSONSuccess(w, contacts, "Contact list retrieved successfully", http.StatusOK) JSONSuccess(w, contacts, "Contact list retrieved successfully", http.StatusOK)
} }
// GetByID godoc
// @Summary Get a contact by ID
// @Description Get a single contact by its ID
// @Tags contacts
// @Accept json
// @Produce json
// @Param id path int true "Contact ID"
// @Success 200 {object} APIResponse{data=models.Contact}
// @Failure 400 {object} APIResponse
// @Failure 404 {object} APIResponse
// @Failure 500 {object} APIResponse
// @Router /contacts/{id} [get]
func (h *ContactHandler) getByID(w http.ResponseWriter, r *http.Request) { func (h *ContactHandler) getByID(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id")) id, err := strconv.Atoi(r.PathValue("id"))
if err != nil { if err != nil {
@@ -56,6 +77,17 @@ func (h *ContactHandler) getByID(w http.ResponseWriter, r *http.Request) {
JSONSuccess(w, contact, "Contact retrieved successfully", http.StatusOK) JSONSuccess(w, contact, "Contact retrieved successfully", http.StatusOK)
} }
// Create godoc
// @Summary Create a new contact
// @Description Create a new contact with the provided data
// @Tags contacts
// @Accept json
// @Produce json
// @Param contact body models.Contact true "Contact object"
// @Success 201 {object} APIResponse{data=models.Contact}
// @Failure 400 {object} APIResponse
// @Failure 500 {object} APIResponse
// @Router /contacts [post]
func (h *ContactHandler) create(w http.ResponseWriter, r *http.Request) { func (h *ContactHandler) create(w http.ResponseWriter, r *http.Request) {
var contact models.Contact var contact models.Contact
@@ -89,6 +121,19 @@ func (h *ContactHandler) create(w http.ResponseWriter, r *http.Request) {
JSONSuccess(w, contact, "Contact created successfully", http.StatusCreated) JSONSuccess(w, contact, "Contact created successfully", http.StatusCreated)
} }
// Update godoc
// @Summary Update a contact
// @Description Update an existing contact by ID
// @Tags contacts
// @Accept json
// @Produce json
// @Param id path int true "Contact ID"
// @Param contact body models.Contact true "Contact object"
// @Success 200 {object} APIResponse
// @Failure 400 {object} APIResponse
// @Failure 404 {object} APIResponse
// @Failure 500 {object} APIResponse
// @Router /contacts/{id} [put]
func (h *ContactHandler) update(w http.ResponseWriter, r *http.Request) { func (h *ContactHandler) update(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id")) id, err := strconv.Atoi(r.PathValue("id"))
if err != nil { if err != nil {
@@ -114,6 +159,18 @@ func (h *ContactHandler) update(w http.ResponseWriter, r *http.Request) {
JSONSuccess(w, nil, "Contact updated successfully", http.StatusOK) JSONSuccess(w, nil, "Contact updated successfully", http.StatusOK)
} }
// Delete godoc
// @Summary Delete a contact
// @Description Delete a contact by ID
// @Tags contacts
// @Accept json
// @Produce json
// @Param id path int true "Contact ID"
// @Success 200 {object} APIResponse
// @Failure 400 {object} APIResponse
// @Failure 404 {object} APIResponse
// @Failure 500 {object} APIResponse
// @Router /contacts/{id} [delete]
func (h *ContactHandler) delete(w http.ResponseWriter, r *http.Request) { func (h *ContactHandler) delete(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id")) id, err := strconv.Atoi(r.PathValue("id"))

View File

@@ -6,15 +6,22 @@ import (
) )
type APIResponse struct { type APIResponse struct {
// Indicates if the request was successful
Success bool `json:"success"` Success bool `json:"success"`
// The response data
Data any `json:"data,omitempty"` Data any `json:"data,omitempty"`
// List of errors if any occurred
Errors []APIError `json:"errors,omitempty"` Errors []APIError `json:"errors,omitempty"`
// Optional message
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
type APIError struct { type APIError struct {
// Error code
Code int `json:"code"` Code int `json:"code"`
// Human-readable error message
Message string `json:"message"` Message string `json:"message"`
// Additional error details
Details string `json:"details,omitempty"` Details string `json:"details,omitempty"`
} }

View File

@@ -1,8 +1,13 @@
package models package models
// Contact represents a contact entity
type Contact struct { type Contact struct {
// ID is the unique identifier for the contact
ID int `json:"id" db:"id"` ID int `json:"id" db:"id"`
// Name of the contact
Name string `json:"name" db:"name"` Name string `json:"name" db:"name"`
// Company the contact works for
Company string `json:"company" db:"company"` Company string `json:"company" db:"company"`
// Phone number in international format
Phone string `json:"phone" db:"phone"` Phone string `json:"phone" db:"phone"`
} }