github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/uaa/internal/routing.go (about) 1 package internal 2 3 import ( 4 "fmt" 5 "io" 6 "net/http" 7 "net/url" 8 "path" 9 "strings" 10 ) 11 12 // Params map path keys to values. For example, if your route has the path 13 // pattern: 14 // /person/:person_id/pets/:pet_type 15 // Then a correct Params map would look like: 16 // router.Params{ 17 // "person_id": "123", 18 // "pet_type": "cats", 19 // } 20 type Params map[string]string 21 22 // Route defines the property of a Cloud Controller V3 endpoint. 23 // 24 // Method can be one of the following: 25 // GET HEAD POST PUT PATCH DELETE CONNECT OPTIONS TRACE 26 // 27 // Path conforms to Pat-style pattern matching. The following docs are taken 28 // from http://godoc.org/github.com/bmizerany/pat#PatternServeMux 29 // 30 // Path Patterns may contain literals or captures. Capture names start with a 31 // colon and consist of letters A-Z, a-z, _, and 0-9. The rest of the pattern 32 // matches literally. The portion of the URL matching each name ends with an 33 // occurrence of the character in the pattern immediately following the name, 34 // or a /, whichever comes first. It is possible for a name to match the empty 35 // string. 36 // 37 // Example pattern with one capture: 38 // /hello/:name 39 // Will match: 40 // /hello/blake 41 // /hello/keith 42 // Will not match: 43 // /hello/blake/ 44 // /hello/blake/foo 45 // /foo 46 // /foo/bar 47 // 48 // Example 2: 49 // /hello/:name/ 50 // Will match: 51 // /hello/blake/ 52 // /hello/keith/foo 53 // /hello/blake 54 // /hello/keith 55 // Will not match: 56 // /foo 57 // /foo/bar 58 type Route struct { 59 // Name is a key specifying which HTTP route the router should associate with 60 // the endpoint at runtime. 61 Name string 62 // Method is any valid HTTP method 63 Method string 64 // Path contains a path pattern 65 Path string 66 // Resource is a key specifying which resource root the router should 67 // associate with the endpoint at runtime. 68 Resource string 69 } 70 71 // CreatePath combines the route's path pattern with a Params map 72 // to produce a valid path. 73 func (r Route) CreatePath(params Params) (string, error) { 74 components := strings.Split(r.Path, "/") 75 for i, c := range components { 76 if len(c) == 0 { 77 continue 78 } 79 if c[0] == ':' { 80 val, ok := params[c[1:]] 81 if !ok { 82 return "", fmt.Errorf("missing param %s", c) 83 } 84 components[i] = val 85 } 86 } 87 88 u, err := url.Parse(strings.Join(components, "/")) 89 if err != nil { 90 return "", err 91 } 92 return u.String(), nil 93 } 94 95 // Router combines route and resource information in order to generate HTTP 96 // requests. 97 type Router struct { 98 routes map[string]Route 99 resources map[string]string 100 } 101 102 // NewRouter returns a pointer to a new Router. 103 func NewRouter(routes []Route, resources map[string]string) *Router { 104 mappedRoutes := map[string]Route{} 105 for _, route := range routes { 106 mappedRoutes[route.Name] = route 107 } 108 return &Router{ 109 routes: mappedRoutes, 110 resources: resources, 111 } 112 } 113 114 // CreateRequest returns a request key'd off of the name given. The params are 115 // merged into the URL and body is set as the request body. 116 func (router Router) CreateRequest(name string, params Params, body io.Reader) (*http.Request, error) { 117 route, ok := router.routes[name] 118 if !ok { 119 return &http.Request{}, fmt.Errorf("No route exists with the name %s", name) 120 } 121 122 uri, err := route.CreatePath(params) 123 if err != nil { 124 return &http.Request{}, err 125 } 126 127 resource, ok := router.resources[route.Resource] 128 if !ok { 129 return &http.Request{}, fmt.Errorf("No resource exists with the name %s", route.Resource) 130 } 131 132 url, err := router.urlFrom(resource, uri) 133 if err != nil { 134 return &http.Request{}, err 135 } 136 137 return http.NewRequest(route.Method, url, body) 138 } 139 140 func (Router) urlFrom(resource string, uri string) (string, error) { 141 u, err := url.Parse(resource) 142 if err != nil { 143 return "", err 144 } 145 u.Path = path.Join(u.Path, uri) 146 return u.String(), nil 147 }