/* * Micro Service * Package: gitlab.hexacode.org/go-libs/microservice * Maintainer: Azzis Arswendo * * Copyright (C) 2023 Hexacode Teknologi Indonesia * All Rights Reserved */ package config import ( "encoding/json" "io" "net/http" "strconv" "github.com/gin-gonic/gin" "gitlab.hexacode.org/go-libs/hctypes" "gitlab.hexacode.org/go-libs/microservice/validate" ) type ConfigContext struct { Method string `json:"method,omitempty"` Url string `json:"url,omitempty"` Config *Config `json:"config,omitempty"` ConfigApi *ConfigAPI `json:"config_api,omitempty"` URLParams hctypes.Dict `json:"url_params,omitempty"` Params hctypes.Dict `json:"params,omitempty"` Headers hctypes.Dict `json:"headers,omitempty"` Request *http.Request `json:"-"` Writer http.ResponseWriter `json:"-"` } type ConfigAPI struct { Name string `json:"name,omitempty"` Path string `json:"path,omitempty"` Method string `json:"method,omitempty"` ContentType string `json:"content_type,omitempty"` ResponseType string `json:"response_type,omitempty"` Timeout string `json:"timeout,omitempty"` Callback *ConfigCallback `json:"callback,omitempty"` Params []*validate.Options `json:"params,omitempty"` URLParams []*validate.Options `json:"url_params,omitempty"` ExtraConfig hctypes.Dict `json:"extra_config,omitempty"` config *Config `json:"-"` } type ReturnHTTPError struct { StatusCode int `json:"status"` Result hctypes.Dict `json:"result,omitempty"` Errors []*ReturnError `json:"errors,omitempty"` } func (config_api *ConfigAPI) ForPublic() *ConfigAPI { return &ConfigAPI{ Name: config_api.Name, Path: config_api.Path, Method: config_api.Method, ContentType: config_api.ContentType, ResponseType: config_api.ResponseType, Params: config_api.Params, URLParams: config_api.URLParams, } } func (config_api *ConfigAPI) ValidParams(data hctypes.Dict) *ReturnError { params_opt := config_api.Params errs := validate.Validate(params_opt, data) if len(errs) > 0 { return &ReturnError{ Name: "params", Errors: errs, } } return nil } func (config_api *ConfigAPI) ValidURLParams(data hctypes.Dict) *ReturnError { params_opt := config_api.URLParams errs := validate.Validate(params_opt, data) if len(errs) > 0 { return &ReturnError{ Name: "url_params", Errors: errs, } } return nil } func (config_api *ConfigAPI) HTTPHandlerConfig(ctx *gin.Context) { render(ctx, config_api.ForPublic()) } func render(ctx *gin.Context, data interface{}) { buff, err := json.Marshal(data) if err != nil { return } ctx.Writer.WriteHeader(http.StatusOK) ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") ctx.Writer.Header().Set("Access-Control-Allow-Methods", "POST, HEAD, PATCH, OPTIONS, GET, PUT, TRACE") ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*") ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true") ctx.Writer.Header().Set("Content-Type", "application/json") ctx.Writer.Header().Set("Content-Length", strconv.Itoa(len(buff))) ctx.Writer.WriteHeaderNow() ctx.Writer.Write(buff) } func options_handler(ctx *gin.Context) { ctx.Writer.WriteHeader(http.StatusOK) ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") ctx.Writer.Header().Set("Access-Control-Allow-Methods", "POST, HEAD, PATCH, OPTIONS, GET, PUT, TRACE") ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*") ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true") ctx.Writer.Header().Set("Content-Length", "0") ctx.Writer.WriteHeaderNow() } func (config_api *ConfigAPI) HTTPHandler(ctx *gin.Context) { url_params := hctypes.Dict{} params := hctypes.Dict{} headers := hctypes.Dict{} raw_headers := ctx.Request.Header.Clone() for k, v := range raw_headers { headers[k] = hctypes.String(v[0]) } for _, param := range ctx.Params { url_params[param.Key] = hctypes.String(param.Value) } ret_err := []*ReturnError{} url_params_err := config_api.ValidURLParams(url_params) if url_params_err != nil { ret_err = append(ret_err, url_params_err) } if config_api.Params != nil { if len(config_api.Params) > 0 { if bytes, err := io.ReadAll(ctx.Request.Body); err == nil { params = hctypes.NewDictFromJson(hctypes.Buffer(bytes)) } else { params = hctypes.Dict{} } } } params_err := config_api.ValidParams(params) if params_err != nil { ret_err = append(ret_err, params_err) } if len(ret_err) > 0 { render(ctx, &ReturnHTTPError{ StatusCode: 400, Errors: ret_err, Result: hctypes.Dict{}, }) return } code, ret, err := config_api.Callback.function(&ConfigContext{ Method: ctx.Request.Method, Url: ctx.Request.URL.Path, Config: config_api.config, ConfigApi: config_api, Params: params, URLParams: url_params, Headers: headers, Request: ctx.Request, Writer: ctx.Writer, }) if err != nil { render(ctx, &err) return } if ret != nil { render(ctx, &ReturnHTTPError{ StatusCode: code, Errors: []*ReturnError{}, Result: ret, }) } } func (ctx *ConfigContext) Error(status int, message string) (int, hctypes.Dict, *ReturnHTTPError) { return status, nil, &ReturnHTTPError{ StatusCode: status, Result: hctypes.Dict{}, Errors: []*ReturnError{ &ReturnError{ Name: ctx.Config.Namespace, Errors: []*validate.ValidateError{ &validate.ValidateError{ Name: ctx.ConfigApi.Name, Message: message, }, }, }, }, } } func (config_api *ConfigAPI) ToDict() hctypes.Dict { bytes, _ := json.Marshal(config_api) return hctypes.NewDictFromJson(hctypes.Buffer(bytes)) }