예제 #1
0
// 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}
}
예제 #2
0
파일: query.go 프로젝트: rs/rest-layer
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,
	})
}
예제 #3
0
파일: types.go 프로젝트: rs/rest-layer
// 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),
		})
	}
}
예제 #4
0
파일: routing.go 프로젝트: rs/rest-layer
// 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
}
예제 #5
0
파일: routing.go 프로젝트: C8E/rest-layer
// 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}
}