Compare commits

...

4 Commits

Author SHA1 Message Date
Florian Beisel c08de78984
📝 Update generated documentation with new Models
This commit contains the new documentation for the API endpoints that
will now use the newly generated models that describe their reponse
correctly
2024-01-18 00:15:14 +01:00
Florian Beisel f0118ab8ea
🐛 Use OldHostname when querying the Database
In BaseRule.baseUpdate our goal is to check if a hostname exists before
trying to rename that hostname into something else. This patch fixes an
error where the newly generated Hostname was used to check for the
existence of the old hostname.
2024-01-18 00:11:39 +01:00
Florian Beisel ce4d469466
🚧 Begin implementing the Models 2024-01-18 00:10:48 +01:00
Florian Beisel 607682884c
📝 Create missing models for API documentation 2024-01-18 00:09:26 +01:00
10 changed files with 279 additions and 123 deletions

View File

@ -6,6 +6,7 @@ import (
"strings"
"git.beisel.it/florian/hostname-service/db"
"git.beisel.it/florian/hostname-service/models"
"git.beisel.it/florian/hostname-service/rules"
"github.com/gin-gonic/gin"
)
@ -65,7 +66,8 @@ func CreateOrUpdateHostname(c *gin.Context, isUpdate bool) {
return
}
c.JSON(http.StatusOK, gin.H{"hostname": hostname})
response := models.SimpleHostnameResponse{Hostname: hostname}
c.JSON(http.StatusOK, response)
}
// @Summary Delete a hostname from the database
@ -74,7 +76,7 @@ func CreateOrUpdateHostname(c *gin.Context, isUpdate bool) {
// @Produce json
// @Param category path string true "Category of the hostname"
// @Param hostname path string true "Hostname to delete"
// @Success 200 {json} json "Hostname"
// @Success 200 {object} models.SimpleHostnameResponse "Hostname"
// @Security Bearer
// @Tags Manipulate existing Hostnames
// @Router /{category}/{hostname} [delete]
@ -87,7 +89,8 @@ func DeleteHostname(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"hostname": hostname})
response := models.SimpleHostnameResponse{Hostname: hostname}
c.JSON(http.StatusOK, response)
}
// @Summary Return a list of hosts and their details filtered by category
@ -95,7 +98,7 @@ func DeleteHostname(c *gin.Context) {
// @ID list-hostnames-by-category
// @Produce json
// @Param category path string true "Category of the hostname"
// @Success 200 {json} json "Hostname"
// @Success 200 {array} models.Hostname "An array of responses"
// @Security Bearer
// @Tags Querying Hostnames
// @Router /{category} [get]
@ -120,8 +123,8 @@ func ListHostnamesByCategory(c *gin.Context) {
// @Produce json
// @Param category path string true "Category of the hostname"
// @Param hostname path string true "Category of the hostname"
// @Success 200 {object} models.Hostname "A single response object"
// @Security Bearer
// @Success 200 {json} json "Hostname"
// @Tags Querying Hostnames
// @Router /{category}/{hostname} [get]
func GetHostnameByCategoryAndName(c *gin.Context) {

View File

@ -12,16 +12,17 @@ import (
)
// LoginHandler godoc
//
// @Summary User login
// @Description Authenticate user and return JWT token
// @Tags Authentication
// @Accept json
// @Produce json
// @Param loginCredentials body models.LoginCredentials true "Login Credentials"
// @Success 200 {object} map[string]string "Successfully authenticated, JWT token returned"
// @Failure 400 {object} map[string]string "Invalid request body"
// @Failure 401 {object} map[string]string "Invalid login credentials"
// @Failure 500 {object} map[string]string "Internal server error"
// @Success 200 {object} models.TokenResponse "Successfully authenticated, JWT token returned"
// @Failure 400 {object} models.ErrorResponse "Invalid request body"
// @Failure 401 {object} models.ErrorResponse "Invalid login credentials"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /login [post]
func LoginHandler(c *gin.Context) {
var creds models.LoginCredentials

View File

@ -52,7 +52,7 @@ const docTemplate = `{
"200": {
"description": "Hostname",
"schema": {
"type": "string"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -85,7 +85,7 @@ const docTemplate = `{
"200": {
"description": "Hostname",
"schema": {
"type": "string"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -148,37 +148,25 @@ const docTemplate = `{
"200": {
"description": "Successfully authenticated, JWT token returned",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.TokenResponse"
}
},
"400": {
"description": "Invalid request body",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
},
"401": {
"description": "Invalid login credentials",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
},
"500": {
"description": "Internal server error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
}
}
@ -211,9 +199,12 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": "Hostname",
"description": "An array of responses",
"schema": {
"type": "json"
"type": "array",
"items": {
"$ref": "#/definitions/models.Hostname"
}
}
}
}
@ -253,9 +244,9 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": "Hostname",
"description": "A single response object",
"schema": {
"type": "json"
"$ref": "#/definitions/models.Hostname"
}
}
}
@ -295,7 +286,7 @@ const docTemplate = `{
"200": {
"description": "Hostname",
"schema": {
"type": "json"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -303,14 +294,72 @@ const docTemplate = `{
}
},
"definitions": {
"models.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"models.Hostname": {
"description": "Model of the Hostname as it is represented in the database",
"type": "object",
"properties": {
"Category": {
"description": "Category / Rule that was used when generating the hostname",
"type": "string",
"example": "notebook"
},
"Created_at": {
"description": "Creation Time of the entry",
"type": "string",
"example": "2024-01-16T12:53:59Z"
},
"Hostname": {
"description": "Generated hostname",
"type": "string",
"example": "ISEHENNB0009"
},
"Id": {
"description": "Internal ID of the Hostname within the database",
"type": "integer",
"example": 25
},
"Parameters": {
"description": "Parameter object of rule specific attributes, see rule.* models",
"type": "object",
"additionalProperties": true
}
}
},
"models.LoginCredentials": {
"description": "User account information used in the login process with Username and password",
"type": "object",
"properties": {
"password": {
"Password": {
"type": "string"
},
"username": {
"Username": {
"type": "string"
}
}
},
"models.SimpleHostnameResponse": {
"description": "Model of the Hostname as returned by POST endpoint",
"type": "object",
"properties": {
"Hostname": {
"description": "Name of the newly generated host",
"type": "string"
}
}
},
"models.TokenResponse": {
"description": "Model returned after successful login",
"type": "object",
"properties": {
"token": {
"type": "string"
}
}

View File

@ -46,7 +46,7 @@
"200": {
"description": "Hostname",
"schema": {
"type": "string"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -79,7 +79,7 @@
"200": {
"description": "Hostname",
"schema": {
"type": "string"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -142,37 +142,25 @@
"200": {
"description": "Successfully authenticated, JWT token returned",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.TokenResponse"
}
},
"400": {
"description": "Invalid request body",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
},
"401": {
"description": "Invalid login credentials",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
},
"500": {
"description": "Internal server error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
"$ref": "#/definitions/models.ErrorResponse"
}
}
}
@ -205,9 +193,12 @@
],
"responses": {
"200": {
"description": "Hostname",
"description": "An array of responses",
"schema": {
"type": "json"
"type": "array",
"items": {
"$ref": "#/definitions/models.Hostname"
}
}
}
}
@ -247,9 +238,9 @@
],
"responses": {
"200": {
"description": "Hostname",
"description": "A single response object",
"schema": {
"type": "json"
"$ref": "#/definitions/models.Hostname"
}
}
}
@ -289,7 +280,7 @@
"200": {
"description": "Hostname",
"schema": {
"type": "json"
"$ref": "#/definitions/models.SimpleHostnameResponse"
}
}
}
@ -297,14 +288,72 @@
}
},
"definitions": {
"models.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"models.Hostname": {
"description": "Model of the Hostname as it is represented in the database",
"type": "object",
"properties": {
"Category": {
"description": "Category / Rule that was used when generating the hostname",
"type": "string",
"example": "notebook"
},
"Created_at": {
"description": "Creation Time of the entry",
"type": "string",
"example": "2024-01-16T12:53:59Z"
},
"Hostname": {
"description": "Generated hostname",
"type": "string",
"example": "ISEHENNB0009"
},
"Id": {
"description": "Internal ID of the Hostname within the database",
"type": "integer",
"example": 25
},
"Parameters": {
"description": "Parameter object of rule specific attributes, see rule.* models",
"type": "object",
"additionalProperties": true
}
}
},
"models.LoginCredentials": {
"description": "User account information used in the login process with Username and password",
"type": "object",
"properties": {
"password": {
"Password": {
"type": "string"
},
"username": {
"Username": {
"type": "string"
}
}
},
"models.SimpleHostnameResponse": {
"description": "Model of the Hostname as returned by POST endpoint",
"type": "object",
"properties": {
"Hostname": {
"description": "Name of the newly generated host",
"type": "string"
}
}
},
"models.TokenResponse": {
"description": "Model returned after successful login",
"type": "object",
"properties": {
"token": {
"type": "string"
}
}

View File

@ -1,12 +1,54 @@
basePath: /api/v1
definitions:
models.ErrorResponse:
properties:
error:
type: string
type: object
models.Hostname:
description: Model of the Hostname as it is represented in the database
properties:
Category:
description: Category / Rule that was used when generating the hostname
example: notebook
type: string
Created_at:
description: Creation Time of the entry
example: "2024-01-16T12:53:59Z"
type: string
Hostname:
description: Generated hostname
example: ISEHENNB0009
type: string
Id:
description: Internal ID of the Hostname within the database
example: 25
type: integer
Parameters:
additionalProperties: true
description: Parameter object of rule specific attributes, see rule.* models
type: object
type: object
models.LoginCredentials:
description: User account information used in the login process with Username
and password
properties:
password:
Password:
type: string
username:
Username:
type: string
type: object
models.SimpleHostnameResponse:
description: Model of the Hostname as returned by POST endpoint
properties:
Hostname:
description: Name of the newly generated host
type: string
type: object
models.TokenResponse:
description: Model returned after successful login
properties:
token:
type: string
type: object
rules.NotebookRuleInput:
@ -43,9 +85,11 @@ paths:
- application/json
responses:
"200":
description: Hostname
description: An array of responses
schema:
type: json
items:
$ref: '#/definitions/models.Hostname'
type: array
security:
- Bearer: []
summary: Return a list of hosts and their details filtered by category
@ -72,7 +116,7 @@ paths:
"200":
description: Hostname
schema:
type: json
$ref: '#/definitions/models.SimpleHostnameResponse'
security:
- Bearer: []
summary: Delete a hostname from the database
@ -96,9 +140,9 @@ paths:
- application/json
responses:
"200":
description: Hostname
description: A single response object
schema:
type: json
$ref: '#/definitions/models.Hostname'
security:
- Bearer: []
summary: Return a single hostname by Category and Name
@ -123,7 +167,7 @@ paths:
"200":
description: Hostname
schema:
type: string
$ref: '#/definitions/models.SimpleHostnameResponse'
summary: Generate hostname for category "notebook"
tags:
- Generating Hostnames
@ -145,7 +189,7 @@ paths:
"200":
description: Hostname
schema:
type: string
$ref: '#/definitions/models.SimpleHostnameResponse'
summary: Update hostname for category "notebook"
tags:
- Generating Hostnames
@ -185,27 +229,19 @@ paths:
"200":
description: Successfully authenticated, JWT token returned
schema:
additionalProperties:
type: string
type: object
$ref: '#/definitions/models.TokenResponse'
"400":
description: Invalid request body
schema:
additionalProperties:
type: string
type: object
$ref: '#/definitions/models.ErrorResponse'
"401":
description: Invalid login credentials
schema:
additionalProperties:
type: string
type: object
$ref: '#/definitions/models.ErrorResponse'
"500":
description: Internal server error
schema:
additionalProperties:
type: string
type: object
$ref: '#/definitions/models.ErrorResponse'
summary: User login
tags:
- Authentication

5
models/error.go Normal file
View File

@ -0,0 +1,5 @@
package models
type ErrorResponse struct {
Error string `json:"error"`
}

View File

@ -6,9 +6,16 @@ import "time"
// @Description Model of the Hostname as it
// @Description is represented in the database
type Hostname struct {
ID int `json:"id"` // Internal ID of the Hostname within the database
Category string `json:"category"` // Category / Rule that was used when generating the hostname
Hostname string `json:"hostname"` // Generated hostname
Parameters map[string]interface{} `json:"parameters"` // Parameter object of rule specific attributes
CreatedAt time.Time `json:"created_at"` // Creation Time of the entry
ID int `json:"Id" example:"25"` // Internal ID of the Hostname within the database
Category string `json:"Category" example:"notebook"` // Category / Rule that was used when generating the hostname
Hostname string `json:"Hostname" example:"ISEHENNB0009"` // Generated hostname
Parameters map[string]interface{} `json:"Parameters"` // Parameter object of rule specific attributes, see rule.* models
CreatedAt time.Time `json:"Created_at" example:"2024-01-16T12:53:59Z"` // Creation Time of the entry
}
// SimpleHostnameResponse
// @Description Model of the Hostname as returned by
// @Description POST endpoint
type SimpleHostnameResponse struct {
Hostname string `json:"Hostname"` // Name of the newly generated host
}

View File

@ -4,6 +4,12 @@ package models
// @Description User account information used in the login process
// @Description with Username and password
type LoginCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
Username string `json:"Username"`
Password string `json:"Password"`
}
// JWT Token Response Model
// @Description Model returned after successful login
type TokenResponse struct {
Token string `json:"token"`
}

View File

@ -32,7 +32,7 @@ func (br *BaseRule) baseInsert(category string, hostname string, paramsJSON []by
}
func (br *BaseRule) baseUpdate(category string, oldhostname string, hostname string, paramsJSON []byte) error {
exists, err := db.HostnameExists(category, hostname)
exists, err := db.HostnameExists(category, oldhostname)
if err != nil {
return fmt.Errorf("error checking existence of hostname: %v", err.Error())
}

View File

@ -73,7 +73,7 @@ func (nr *NotebookRule) Generate(params map[string]interface{}) (string, []byte,
// @Produce json
// @Tags Generating Hostnames
// @Param body body NotebookRuleInput true "Input data to generate hostname"
// @Success 200 {string} string "Hostname"
// @Success 200 {object} models.SimpleHostnameResponse "Hostname"
// @Router /api/notebook [post]
func (nr *NotebookRule) Insert(category string, hostname string, paramsJSON []byte) error {
return nr.baseInsert(category, hostname, paramsJSON)
@ -86,7 +86,7 @@ func (nr *NotebookRule) Insert(category string, hostname string, paramsJSON []by
// @Produce json
// @Tags Generating Hostnames
// @Param body body NotebookRuleInput true "Input data to generate hostname"
// @Success 200 {string} string "Hostname"
// @Success 200 {object} models.SimpleHostnameResponse "Hostname"
// @Router /api/notebook [put]
func (nr *NotebookRule) Update(category string, oldhostname string, hostname string, paramsJSON []byte) error {
return nr.baseUpdate(category, oldhostname, hostname, paramsJSON)