aicra/config/services.go

80 lines
1.9 KiB
Go
Raw Normal View History

package config
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
// Parse builds a server configuration from a json reader and checks for most format errors.
func Parse(r io.Reader) (Services, error) {
services := make(Services, 0)
err := json.NewDecoder(r).Decode(&services)
if err != nil {
return nil, fmt.Errorf("%s: %w", ErrRead, err)
}
err = services.checkAndFormat()
if err != nil {
return nil, fmt.Errorf("%s: %w", ErrFormat, err)
}
if services.collide() {
return nil, fmt.Errorf("%s: %w", ErrFormat, ErrPatternCollision)
}
return services, nil
}
// collide returns if there is collision between services
func (svc Services) collide() bool {
// todo: implement pattern collision using types to check if braces can be equal to fixed uri parts
return false
}
// Find a service matching an incoming HTTP request
func (svc Services) Find(r *http.Request) *Service {
for _, service := range svc {
if service.Match(r) {
return service
}
}
return nil
}
// checkAndFormat checks for errors and missing fields and sets default values for optional fields.
func (svc Services) checkAndFormat() error {
for _, service := range svc {
// check method
err := service.checkMethod()
if err != nil {
return fmt.Errorf("%s '%s' [method]: %w", service.Method, service.Pattern, err)
}
// check pattern
service.Pattern = strings.Trim(service.Pattern, " \t\r\n")
err = service.checkPattern()
if err != nil {
return fmt.Errorf("%s '%s' [path]: %w", service.Method, service.Pattern, err)
}
// check description
if len(strings.Trim(service.Description, " \t\r\n")) < 1 {
return fmt.Errorf("%s '%s' [description]: %w", service.Method, service.Pattern, ErrMissingDescription)
}
// check input parameters
err = service.checkAndFormatInput()
if err != nil {
return fmt.Errorf("%s '%s' [in]: %w", service.Method, service.Pattern, err)
}
}
return nil
}