wip: add api auth and /resume endpoint
This commit is contained in:
parent
22e2f6005f
commit
aaec8ec08d
23 changed files with 1244 additions and 271 deletions
43
internal/delivery/http/handler.go
Normal file
43
internal/delivery/http/handler.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"git.roboces.dev/catalin/cvvvvv/internal/config"
|
||||
v1 "git.roboces.dev/catalin/cvvvvv/internal/delivery/http/v1"
|
||||
"git.roboces.dev/catalin/cvvvvv/internal/service"
|
||||
"git.roboces.dev/catalin/cvvvvv/pkg/limiter"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
services *service.Services
|
||||
}
|
||||
|
||||
func NewHandler(services *service.Services) *Handler {
|
||||
return &Handler{
|
||||
services: services,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) Init(cfg *config.Config) *gin.Engine {
|
||||
// Init gin handler
|
||||
router := gin.Default()
|
||||
|
||||
router.Use(
|
||||
gin.Recovery(),
|
||||
gin.Logger(),
|
||||
limiter.Limit(cfg.Limiter.RPS, cfg.Limiter.Burst, cfg.Limiter.TTL),
|
||||
corsMiddleware,
|
||||
)
|
||||
|
||||
h.initAPI(router)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func (h *Handler) initAPI(router *gin.Engine) {
|
||||
handlerV1 := v1.NewHandler(h.services)
|
||||
api := router.Group("/api")
|
||||
{
|
||||
handlerV1.Init(api)
|
||||
}
|
||||
}
|
||||
20
internal/delivery/http/middleware.go
Normal file
20
internal/delivery/http/middleware.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func corsMiddleware(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Access-Control-Allow-Methods", "*")
|
||||
c.Header("Access-Control-Allow-Headers", "*")
|
||||
c.Header("Content-Type", "application/json")
|
||||
|
||||
if c.Request.Method != "OPTIONS" {
|
||||
c.Next()
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
}
|
||||
}
|
||||
25
internal/delivery/http/v1/handler.go
Normal file
25
internal/delivery/http/v1/handler.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"git.roboces.dev/catalin/cvvvvv/internal/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
services *service.Services
|
||||
}
|
||||
|
||||
func NewHandler(services *service.Services) *Handler {
|
||||
return &Handler{
|
||||
services: services,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) Init(api *gin.RouterGroup) {
|
||||
v1 := api.Group("/v1")
|
||||
{
|
||||
v1.GET("/usage", h.getUsage)
|
||||
v1.GET("/ping", h.getPing)
|
||||
v1.GET("/resume", h.getResume)
|
||||
}
|
||||
}
|
||||
30
internal/delivery/http/v1/middleware.go
Normal file
30
internal/delivery/http/v1/middleware.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func containsValue(m map[string]string, value string) (string, error) {
|
||||
for _, v := range m {
|
||||
if v == value {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return value, errors.New("value is not in the provided map")
|
||||
}
|
||||
|
||||
func (h *Handler) VerifyAuthentication(ctx *gin.Context) (string, error) {
|
||||
header := ctx.GetHeader("X-API-KEY")
|
||||
if header != "" {
|
||||
return containsValue(h.services.Config.Auth.ApiKeys, header)
|
||||
}
|
||||
|
||||
key := ctx.Query("api_key")
|
||||
if key != "" {
|
||||
return containsValue(h.services.Config.Auth.ApiKeys, key)
|
||||
}
|
||||
|
||||
return "", errors.New("Missing API key")
|
||||
}
|
||||
12
internal/delivery/http/v1/ping.go
Normal file
12
internal/delivery/http/v1/ping.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (h *Handler) getPing(c *gin.Context) {
|
||||
c.Writer.Header().Set("Content-Type", "text/plain")
|
||||
c.String(http.StatusOK, "pong")
|
||||
}
|
||||
19
internal/delivery/http/v1/response.go
Normal file
19
internal/delivery/http/v1/response.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"git.roboces.dev/catalin/cvvvvv/pkg/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type dataResponse struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func newResponse(c *gin.Context, statusCode int, message string) {
|
||||
logger.Error(message)
|
||||
c.AbortWithStatusJSON(statusCode, response{message})
|
||||
}
|
||||
24
internal/delivery/http/v1/resume.go
Normal file
24
internal/delivery/http/v1/resume.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.roboces.dev/catalin/cvvvvv/internal/domain"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ResumeResponse struct {
|
||||
Resume domain.Resume `json:"resume"`
|
||||
}
|
||||
|
||||
func (h *Handler) getResume(ctx *gin.Context) {
|
||||
|
||||
_, err := h.VerifyAuthentication(ctx)
|
||||
if err != nil {
|
||||
newResponse(ctx, http.StatusUnauthorized, "Api key not provided or invalid")
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, ResumeResponse{
|
||||
Resume: h.services.Resumes.Get(),
|
||||
})
|
||||
}
|
||||
25
internal/delivery/http/v1/usage.go
Normal file
25
internal/delivery/http/v1/usage.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (h *Handler) getUsage(c *gin.Context) {
|
||||
c.Writer.Header().Set("Content-Type", "text/plain")
|
||||
message := fmt.Sprintf(`
|
||||
Hello! If you're seeing this message it means you are authorized to view my CV.
|
||||
You should have been provided an api key in order to query the different endpoints,
|
||||
which are not public. You can put the key into a X-API-KEY header or use it
|
||||
as a query param. Examples:
|
||||
|
||||
curl %s/api/v1/usage -H "X-API-KEY: verysecret"
|
||||
|
||||
curl %s/api/v1/usage?api_key=verysecret
|
||||
|
||||
`, c.Request.Host, c.Request.Host)
|
||||
|
||||
c.String(http.StatusOK, message)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue