// findRoute recursively route a (sub)resource request func findRoute(path string, index resource.Index, route *RouteMatch) *Error { // Split the path into path components c := strings.Split(strings.Trim(path, "/"), "/") // Shift the resource name from the path components name, c := c[0], c[1:] resourcePath := name if prefix := route.ResourcePath.Path(); prefix != "" { resourcePath = strings.Join([]string{prefix, name}, ".") } // First component must match a resource if rsrc, _, found := index.GetResource(resourcePath); found { if len(c) >= 1 { // If there are some components left, the path targets an item or an alias // Shift the item id from the path components var id string id, c = c[0], c[1:] // Handle sub-resources (/resource1/id1/resource2/id2) if len(c) >= 1 { subResourcePath := strings.Join([]string{resourcePath, c[0]}, ".") if _, field, found := index.GetResource(subResourcePath); found { // Append the intermediate resource path route.ResourcePath.append(rsrc, field, id, name) // Recurse to match the sub-path path = strings.Join(c, "/") if err := findRoute(path, index, route); err != nil { return err } } else { route.ResourcePath.clear() return &Error{404, "Resource Not Found", nil} } return nil } // Handle aliases (/resource/alias or /resource1/id1/resource2/alias) if alias, found := rsrc.GetAlias(id); found { // Apply aliases query to the request for key, values := range alias { for _, value := range values { route.Params.Add(key, value) } } } else { // Set the id route field route.ResourcePath.append(rsrc, "id", id, name) return nil } } // Set the collection resource route.ResourcePath.append(rsrc, "", nil, name) return nil } route.ResourcePath.clear() return &Error{404, "Resource Not Found", nil} }
func newRootQuery(idx resource.Index) *graphql.Object { t := types{} if c, ok := idx.(schema.Compiler); ok { if err := c.Compile(); err != nil { log.Fatal(err) } } flds := graphql.Fields{} for _, r := range idx.GetResources() { if r.Conf().IsModeAllowed(resource.Read) { flds[r.Name()] = t.getGetQuery(idx, r) } if r.Conf().IsModeAllowed(resource.List) { flds[r.Name()+"List"] = t.getListQuery(idx, r, nil) for _, a := range r.GetAliases() { params, _ := r.GetAlias(a) flds[r.Name()+strings.Title(a)] = t.getListQuery(idx, r, params) } } } return graphql.NewObject(graphql.ObjectConfig{ Name: "RootQuery", Fields: flds, }) }
// addConnections adds connections fields to the object afterward to prevent from dead loops func (t types) addConnections(o *graphql.Object, idx resource.Index, r *resource.Resource) { // Add sub field references for name, def := range r.Schema().Fields { if ref, ok := def.Validator.(*schema.Reference); ok { sr, found := idx.GetResource(ref.Path, nil) if !found { log.Panicf("resource reference not found: %s", ref.Path) } o.AddFieldConfig(name, &graphql.Field{ Description: def.Description, Type: t.getObjectType(idx, sr), Args: getFArgs(def.Params), Resolve: getSubFieldResolver(name, sr, def), }) } } // Add sub resources for _, sr := range r.GetResources() { name := sr.Name() o.AddFieldConfig(name, &graphql.Field{ Description: fmt.Sprintf("Connection to %s", name), Type: graphql.NewList(t.getObjectType(idx, sr)), Args: listArgs, Resolve: getSubResourceResolver(sr), }) } }
// findRoute recursively route a (sub)resource request func findRoute(path string, index resource.Index, route *RouteMatch) error { // Extract the first component of the path var name string name, path = nextPathComponent(path) resourcePath := name if prefix := route.ResourcePath.Path(); prefix != "" { resourcePath = prefix + "." + name } if rsrc, found := index.GetResource(resourcePath, nil); found { // First component must match a resource if len(path) >= 1 { // If there are some components left, the path targets an item or an alias // Shift the item id from the path components var id string id, path = nextPathComponent(path) // Handle sub-resources (/resource1/id1/resource2/id2) if len(path) >= 1 { subPathComp, _ := nextPathComponent(path) subResourcePath := resourcePath + "." + subPathComp if subResource, found := index.GetResource(subResourcePath, nil); found { // Append the intermediate resource path route.ResourcePath.append(rsrc, subResource.ParentField(), id, name) // Recurse to match the sub-path if err := findRoute(path, index, route); err != nil { return err } } else { route.ResourcePath.clear() return errResourceNotFound } return nil } // Handle aliases (/resource/alias or /resource1/id1/resource2/alias) if alias, found := rsrc.GetAlias(id); found { // Apply aliases query to the request for key, values := range alias { for _, value := range values { route.Params.Add(key, value) } } } else { // Set the id route field route.ResourcePath.append(rsrc, "id", id, name) return nil } } // Set the collection resource route.ResourcePath.append(rsrc, "", nil, name) return nil } route.ResourcePath.clear() return errResourceNotFound }
// findRoute recursively route a (sub)resource request func findRoute(ctx context.Context, path string, index resource.Index, route *RouteMatch) *Error { // Split the path into path components c := strings.Split(strings.Trim(path, "/"), "/") // Shift the resource name from the path components name, c := c[0], c[1:] resourcePath := name if prefix := route.ResourcePath.Path(); prefix != "" { resourcePath = strings.Join([]string{prefix, name}, ".") } // First component must match a resource if rsrc, _, found := index.GetResource(resourcePath); found { rp := ResourcePathComponent{ Name: name, Resource: rsrc, } if len(c) >= 1 { // If there are some components left, the path targets an item or an alias // Shift the item id from the path components var id string id, c = c[0], c[1:] // Handle sub-resources (/resource1/id1/resource2/id2) if len(c) >= 1 { subResourcePath := strings.Join([]string{resourcePath, c[0]}, ".") if _, field, found := index.GetResource(subResourcePath); found { // Check if the current (intermediate) item exists before going farther l := resource.NewLookup() q := schema.Query{} for _, rp := range route.ResourcePath { if rp.Value != nil { q = append(q, schema.Equal{Field: rp.Field, Value: rp.Value}) } } q = append(q, schema.Equal{Field: "id", Value: id}) l.AddQuery(q) list, err := rsrc.Find(ctx, l, 1, 1) if err != nil { return NewError(err) } else if len(list.Items) == 0 { return ErrNotFound } rp.Field = field rp.Value = id route.ResourcePath = append(route.ResourcePath, rp) // Recurse to match the sub-path path = strings.Join(c, "/") if err := findRoute(ctx, path, index, route); err != nil { return err } } else { route.ResourcePath = ResourcePath{} return &Error{404, "Resource Not Found", nil} } return nil } // Handle aliases (/resource/alias or /resource1/id1/resource2/alias) if alias, found := rsrc.GetAlias(id); found { // Apply aliases query to the request for key, values := range alias { for _, value := range values { route.Params.Add(key, value) } } } else { // Set the id route field rp.Field = "id" rp.Value = id } } route.ResourcePath = append(route.ResourcePath, rp) return nil } route.ResourcePath = ResourcePath{} return &Error{404, "Resource Not Found", nil} }