...

Source file src/gitlab.hexacode.org/go-libs/microservice/config/config_api.go

Documentation: gitlab.hexacode.org/go-libs/microservice/config

     1  /*
     2   * Micro Service
     3   * Package: gitlab.hexacode.org/go-libs/microservice
     4   * Maintainer: Azzis Arswendo <azzis@hexacode.org>
     5   *
     6   * Copyright (C) 2023 Hexacode Teknologi Indonesia
     7   * All Rights Reserved
     8   */
     9  
    10  package config
    11  
    12  import (
    13  	"encoding/json"
    14  	"io"
    15  	"net/http"
    16  	"strconv"
    17  
    18  	"github.com/gin-gonic/gin"
    19  	"gitlab.hexacode.org/go-libs/hctypes"
    20  	"gitlab.hexacode.org/go-libs/microservice/validate"
    21  )
    22  
    23  type ConfigContext struct {
    24  	Method    string              `json:"method,omitempty"`
    25  	Url       string              `json:"url,omitempty"`
    26  	Config    *Config             `json:"config,omitempty"`
    27  	ConfigApi *ConfigAPI          `json:"config_api,omitempty"`
    28  	URLParams hctypes.Dict        `json:"url_params,omitempty"`
    29  	Params    hctypes.Dict        `json:"params,omitempty"`
    30  	Headers   hctypes.Dict        `json:"headers,omitempty"`
    31  	Request   *http.Request       `json:"-"`
    32  	Writer    http.ResponseWriter `json:"-"`
    33  }
    34  
    35  type ConfigAPI struct {
    36  	Name         string              `json:"name,omitempty"`
    37  	Path         string              `json:"path,omitempty"`
    38  	Method       string              `json:"method,omitempty"`
    39  	ContentType  string              `json:"content_type,omitempty"`
    40  	ResponseType string              `json:"response_type,omitempty"`
    41  	Timeout      string              `json:"timeout,omitempty"`
    42  	Callback     *ConfigCallback     `json:"callback,omitempty"`
    43  	Params       []*validate.Options `json:"params,omitempty"`
    44  	URLParams    []*validate.Options `json:"url_params,omitempty"`
    45  	ExtraConfig  hctypes.Dict        `json:"extra_config,omitempty"`
    46  	config       *Config             `json:"-"`
    47  }
    48  
    49  type ReturnHTTPError struct {
    50  	StatusCode int            `json:"status"`
    51  	Result     hctypes.Dict   `json:"result,omitempty"`
    52  	Errors     []*ReturnError `json:"errors,omitempty"`
    53  }
    54  
    55  func (config_api *ConfigAPI) ForPublic() *ConfigAPI {
    56  	return &ConfigAPI{
    57  		Name:         config_api.Name,
    58  		Path:         config_api.Path,
    59  		Method:       config_api.Method,
    60  		ContentType:  config_api.ContentType,
    61  		ResponseType: config_api.ResponseType,
    62  		Params:       config_api.Params,
    63  		URLParams:    config_api.URLParams,
    64  	}
    65  }
    66  
    67  func (config_api *ConfigAPI) ValidParams(data hctypes.Dict) *ReturnError {
    68  	params_opt := config_api.Params
    69  
    70  	errs := validate.Validate(params_opt, data)
    71  	if len(errs) > 0 {
    72  		return &ReturnError{
    73  			Name:   "params",
    74  			Errors: errs,
    75  		}
    76  	}
    77  
    78  	return nil
    79  }
    80  
    81  func (config_api *ConfigAPI) ValidURLParams(data hctypes.Dict) *ReturnError {
    82  	params_opt := config_api.URLParams
    83  
    84  	errs := validate.Validate(params_opt, data)
    85  	if len(errs) > 0 {
    86  		return &ReturnError{
    87  			Name:   "url_params",
    88  			Errors: errs,
    89  		}
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func (config_api *ConfigAPI) HTTPHandlerConfig(ctx *gin.Context) {
    96  	render(ctx, config_api.ForPublic())
    97  }
    98  
    99  func render(ctx *gin.Context, data interface{}) {
   100  	buff, err := json.Marshal(data)
   101  	if err != nil {
   102  		return
   103  	}
   104  
   105  	ctx.Writer.WriteHeader(http.StatusOK)
   106  	ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
   107  	ctx.Writer.Header().Set("Access-Control-Allow-Methods", "POST, HEAD, PATCH, OPTIONS, GET, PUT, TRACE")
   108  	ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*")
   109  	ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
   110  	ctx.Writer.Header().Set("Content-Type", "application/json")
   111  	ctx.Writer.Header().Set("Content-Length", strconv.Itoa(len(buff)))
   112  	ctx.Writer.WriteHeaderNow()
   113  	ctx.Writer.Write(buff)
   114  }
   115  
   116  func options_handler(ctx *gin.Context) {
   117  	ctx.Writer.WriteHeader(http.StatusOK)
   118  	ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
   119  	ctx.Writer.Header().Set("Access-Control-Allow-Methods", "POST, HEAD, PATCH, OPTIONS, GET, PUT, TRACE")
   120  	ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*")
   121  	ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
   122  	ctx.Writer.Header().Set("Content-Length", "0")
   123  	ctx.Writer.WriteHeaderNow()
   124  }
   125  
   126  func (config_api *ConfigAPI) HTTPHandler(ctx *gin.Context) {
   127  	url_params := hctypes.Dict{}
   128  	params := hctypes.Dict{}
   129  	headers := hctypes.Dict{}
   130  
   131  	raw_headers := ctx.Request.Header.Clone()
   132  
   133  	for k, v := range raw_headers {
   134  		headers[k] = hctypes.String(v[0])
   135  	}
   136  
   137  	for _, param := range ctx.Params {
   138  		url_params[param.Key] = hctypes.String(param.Value)
   139  	}
   140  
   141  	ret_err := []*ReturnError{}
   142  
   143  	url_params_err := config_api.ValidURLParams(url_params)
   144  	if url_params_err != nil {
   145  		ret_err = append(ret_err, url_params_err)
   146  	}
   147  
   148  	if config_api.Params != nil {
   149  		if len(config_api.Params) > 0 {
   150  			if bytes, err := io.ReadAll(ctx.Request.Body); err == nil {
   151  				params = hctypes.NewDictFromJson(hctypes.Buffer(bytes))
   152  			} else {
   153  				params = hctypes.Dict{}
   154  			}
   155  		}
   156  	}
   157  
   158  	params_err := config_api.ValidParams(params)
   159  	if params_err != nil {
   160  		ret_err = append(ret_err, params_err)
   161  	}
   162  
   163  	if len(ret_err) > 0 {
   164  		render(ctx, &ReturnHTTPError{
   165  			StatusCode: 400,
   166  			Errors:     ret_err,
   167  			Result:     hctypes.Dict{},
   168  		})
   169  		return
   170  	}
   171  
   172  	code, ret, err := config_api.Callback.function(&ConfigContext{
   173  		Method:    ctx.Request.Method,
   174  		Url:       ctx.Request.URL.Path,
   175  		Config:    config_api.config,
   176  		ConfigApi: config_api,
   177  		Params:    params,
   178  		URLParams: url_params,
   179  		Headers:   headers,
   180  		Request:   ctx.Request,
   181  		Writer:    ctx.Writer,
   182  	})
   183  
   184  	if err != nil {
   185  		render(ctx, &err)
   186  		return
   187  	}
   188  
   189  	if ret != nil {
   190  		render(ctx, &ReturnHTTPError{
   191  			StatusCode: code,
   192  			Errors:     []*ReturnError{},
   193  			Result:     ret,
   194  		})
   195  	}
   196  }
   197  
   198  func (ctx *ConfigContext) Error(status int, message string) (int, hctypes.Dict, *ReturnHTTPError) {
   199  	return status, nil, &ReturnHTTPError{
   200  		StatusCode: status,
   201  		Result:     hctypes.Dict{},
   202  		Errors: []*ReturnError{
   203  			&ReturnError{
   204  				Name: ctx.Config.Namespace,
   205  				Errors: []*validate.ValidateError{
   206  					&validate.ValidateError{
   207  						Name:    ctx.ConfigApi.Name,
   208  						Message: message,
   209  					},
   210  				},
   211  			},
   212  		},
   213  	}
   214  }
   215  
   216  func (config_api *ConfigAPI) ToDict() hctypes.Dict {
   217  	bytes, _ := json.Marshal(config_api)
   218  	return hctypes.NewDictFromJson(hctypes.Buffer(bytes))
   219  }
   220  

View as plain text