grokify/mogo

View on GitHub
api/path_to_pattern.go

Summary

Maintainability
A
0 mins
Test Coverage
package api

import (
    "regexp"
    "strings"

    "github.com/grokify/mogo/type/stringsutil"
)

const (
    rxMatchParameterPattern = `{[^\{\}/]*?}`
    rxMatchParameterActual  = `[^\{\}/]*?`
)

// URLTransformer is useful for reading log files and converting actual
// request URls into pattners, such as those used in the OpenAPI Spec for
// reporting and categorization purposes.
type URLTransformer struct {
    ExactPaths     []string
    RegexpPaths    map[string]*regexp.Regexp
    rxMatchPattern *regexp.Regexp
    rxMatchActual  *regexp.Regexp
    rxStripQuery   *regexp.Regexp
}

// NewURLTransformer creates a new URLTransformer instance.
func NewURLTransformer() URLTransformer {
    return URLTransformer{
        ExactPaths:     []string{},
        RegexpPaths:    map[string]*regexp.Regexp{},
        rxMatchPattern: regexp.MustCompile(rxMatchParameterPattern),
        rxMatchActual:  regexp.MustCompile(rxMatchParameterActual),
        rxStripQuery:   regexp.MustCompile(`\?.*$`)}
}

// LoadPaths loads multiple spec URL patterns. See the test file for an example.
func (ut *URLTransformer) LoadPaths(paths []string) error {
    for _, path := range paths {
        err := ut.LoadPath(path)
        if err != nil {
            return err
        }
    }
    return nil
}

// LoadPath loads a single spec URL pattern.
func (ut *URLTransformer) LoadPath(path string) error {
    path = ut.rxStripQuery.ReplaceAllString(path, "")
    i1 := strings.Index(path, "{")
    i2 := strings.Index(path, "}")
    if i1 < 0 && i2 < 0 {
        ut.ExactPaths = append(ut.ExactPaths, path)
        return nil
    }
    linkPattern := ut.rxMatchPattern.ReplaceAllString(path, rxMatchParameterActual)
    linkPattern = `^` + linkPattern + `$`
    rx, err := regexp.Compile(linkPattern)
    if err != nil {
        return err
    }
    ut.RegexpPaths[path] = rx
    return nil
}

// URLActualToPattern is the "runtime" API that is called over and over
// for URL classification purposes.
func (ut *URLTransformer) URLActualToPattern(s string) string {
    s = ut.rxStripQuery.ReplaceAllString(s, "")
    for _, try := range ut.ExactPaths {
        if s == try {
            return s
        }
    }
    for pattern, rx := range ut.RegexpPaths {
        if rx.MatchString(s) {
            return pattern
        }
    }
    return s
}

func (ut *URLTransformer) BuildReverseEndpointPattern(method, actualURL string) string {
    pattern := ut.URLActualToPattern(actualURL)
    return strings.Join(
        stringsutil.SliceCondenseSpace([]string{pattern, method}, false, false),
        " ")
    // join.JoinCondenseTrimSpace([]string{pattern, method}, " ")
}