@@ -20,12 +20,69 @@ import (
2020 "context"
2121 "fmt"
2222 "maps"
23+ "net/url"
24+ "strings"
2325
2426 "github.com/firebase/genkit/go/core"
2527 "github.com/firebase/genkit/go/core/api"
26- coreresource "github.com/firebase/genkit/go/core/resource "
28+ "github.com/yosida95/uritemplate/v3 "
2729)
2830
31+ // normalizeURI normalizes a URI for template matching by removing query parameters,
32+ // fragments, and trailing slashes from the path.
33+ func normalizeURI (rawURI string ) string {
34+ // Parse the URI
35+ u , err := url .Parse (rawURI )
36+ if err != nil {
37+ // If parsing fails, return the original URI
38+ return rawURI
39+ }
40+
41+ // Remove query parameters and fragment
42+ u .RawQuery = ""
43+ u .Fragment = ""
44+
45+ // Remove trailing slash from path (but not from the root path)
46+ if len (u .Path ) > 1 && strings .HasSuffix (u .Path , "/" ) {
47+ u .Path = strings .TrimSuffix (u .Path , "/" )
48+ }
49+
50+ return u .String ()
51+ }
52+
53+ // matches checks if a URI matches the given URI template.
54+ func matches (templateStr , uri string ) (bool , error ) {
55+ template , err := uritemplate .New (templateStr )
56+ if err != nil {
57+ return false , fmt .Errorf ("invalid URI template %q: %w" , templateStr , err )
58+ }
59+
60+ normalizedURI := normalizeURI (uri )
61+ values := template .Match (normalizedURI )
62+ return len (values ) > 0 , nil
63+ }
64+
65+ // extractVariables extracts variables from a URI using the given URI template.
66+ func extractVariables (templateStr , uri string ) (map [string ]string , error ) {
67+ template , err := uritemplate .New (templateStr )
68+ if err != nil {
69+ return nil , fmt .Errorf ("invalid URI template %q: %w" , templateStr , err )
70+ }
71+
72+ normalizedURI := normalizeURI (uri )
73+ values := template .Match (normalizedURI )
74+ if len (values ) == 0 {
75+ return nil , fmt .Errorf ("URI %q does not match template" , uri )
76+ }
77+
78+ // Convert uritemplate.Values to string map
79+ result := make (map [string ]string )
80+ for name , value := range values {
81+ result [name ] = value .String ()
82+ }
83+ return result , nil
84+ }
85+
2986// ResourceInput represents the input to a resource function.
3087type ResourceInput struct {
3188 URI string `json:"uri"` // The resource URI
@@ -129,11 +186,11 @@ func (r *resource) Matches(uri string) bool {
129186
130187 // Check template
131188 if template , ok := resourceMeta ["template" ].(string ); ok && template != "" {
132- matcher , err := coreresource . NewTemplateMatcher (template )
189+ matches , err := matches (template , uri )
133190 if err != nil {
134191 return false
135192 }
136- return matcher . Matches ( uri )
193+ return matches
137194 }
138195
139196 return false
@@ -156,11 +213,7 @@ func (r *resource) ExtractVariables(uri string) (map[string]string, error) {
156213
157214 // Extract from template
158215 if template , ok := resourceMeta ["template" ].(string ); ok && template != "" {
159- matcher , err := coreresource .NewTemplateMatcher (template )
160- if err != nil {
161- return nil , fmt .Errorf ("invalid template %q: %w" , template , err )
162- }
163- return matcher .ExtractVariables (uri )
216+ return extractVariables (template , uri )
164217 }
165218
166219 return nil , fmt .Errorf ("no URI or template found in resource metadata" )
0 commit comments