Beispiel #1
0
// Analyze an attribute, create corresponding ActionParam
func (a *ApiAnalyzer) AnalyzeAttribute(name, query string, attr map[string]interface{}) (*gen.ActionParam, error) {
	param := gen.ActionParam{Name: name, QueryName: query, VarName: toVarName(name)}
	if d, ok := attr["description"]; ok {
		param.Description = removeBlankLines(d.(string))
	}
	if r, ok := attr["required"]; ok {
		if r.(bool) {
			param.Mandatory = true
		}
	}
	if options, ok := attr["options"]; ok {
		opts, ok := options.(map[string]interface{})
		if ok {
			for n, o := range opts {
				switch n {
				case "max":
					param.Max = int(o.(float64))
				case "min":
					param.Min = int(o.(float64))
				case "regexp":
					param.Regexp = o.(string)
				}
			}
		}
	}
	if values, ok := attr["values"]; ok {
		param.ValidValues = values.([]interface{})
	}
	t := attr["type"].(map[string]interface{})
	dataType, err := a.AnalyzeType(t, query)
	if err != nil {
		return nil, err
	}
	param.Type = dataType
	switch dataType.(type) {
	case *gen.ArrayDataType:
		param.QueryName += "[]"
	}

	return &param, nil
}
Beispiel #2
0
// AnalyzeResource analyzes the given resource and updates the Resources and ParamTypes analyzer
// fields accordingly
func (a *APIAnalyzer) AnalyzeResource(name string, resource interface{}, descriptor *gen.APIDescriptor) {
	var res = resource.(map[string]interface{})

	// Compute description
	var description string
	if d, ok := res["description"].(string); ok {
		description = d
	}

	// Compute attributes
	var attributes []*gen.Attribute
	var atts map[string]interface{}
	if m, ok := res["media_type"].(map[string]interface{}); ok {
		atts = m["attributes"].(map[string]interface{})
		attributes = make([]*gen.Attribute, len(atts))
		for idx, n := range sortedKeys(atts) {
			at, ok := a.attributeTypes[n+"#"+name]
			if !ok {
				at = a.attributeTypes[n]
			}
			attributes[idx] = &gen.Attribute{n, inflect.Camelize(n), at}
		}
	} else {
		attributes = []*gen.Attribute{}
	}

	// Compute actions
	var methods = res["methods"].(map[string]interface{})
	var actionNames = sortedKeys(methods)
	var actions = []*gen.Action{}
	for _, actionName := range actionNames {
		var m = methods[actionName]
		var meth = m.(map[string]interface{})
		var params map[string]interface{}
		if p, ok := meth["parameters"]; ok {
			params = p.(map[string]interface{})
		}
		var description = "No description provided for " + actionName + "."
		if d, _ := meth["description"]; d != nil {
			description = d.(string)
		}
		var pathPatterns = ParseRoute(fmt.Sprintf("%s#%s", name, actionName),
			meth["route"].(string))
		if len(pathPatterns) == 0 {
			// Custom action
			continue
		}
		var allParamNames = make([]string, len(params))
		var i = 0
		for n := range params {
			allParamNames[i] = n
			i++
		}
		sort.Strings(allParamNames)

		var contentType string
		if c, ok := meth["content_type"].(string); ok {
			contentType = c
		}
		var paramAnalyzer = NewAnalyzer(params)
		paramAnalyzer.Analyze()

		// Record new parameter types
		var paramTypeNames = make([]string, len(paramAnalyzer.ParamTypes))
		var idx = 0
		for n := range paramAnalyzer.ParamTypes {
			paramTypeNames[idx] = n
			idx++
		}
		sort.Strings(paramTypeNames)
		for _, name := range paramTypeNames {
			var pType = paramAnalyzer.ParamTypes[name]
			if _, ok := a.rawTypes[name]; ok {
				a.rawTypes[name] = append(a.rawTypes[name], pType)
			} else {
				a.rawTypes[name] = []*gen.ObjectDataType{pType}
			}
		}

		// Update description with parameter descriptions
		var mandatory []string
		var optional []string
		for _, p := range paramAnalyzer.Params {
			if p.Mandatory {
				desc := p.Name
				if p.Description != "" {
					desc += ": " + strings.TrimSpace(p.Description)
				}
				mandatory = append(mandatory, desc)
			} else {
				desc := p.Name
				if p.Description != "" {
					desc += ": " + strings.TrimSpace(p.Description)
				}
				optional = append(optional, desc)
			}
		}
		if len(mandatory) > 0 {
			sort.Strings(mandatory)
			if !strings.HasSuffix(description, "\n") {
				description += "\n"
			}
			description += "Required parameters:\n\t" + strings.Join(mandatory, "\n\t")
		}
		if len(optional) > 0 {
			sort.Strings(optional)
			if !strings.HasSuffix(description, "\n") {
				description += "\n"
			}
			description += "Optional parameters:\n\t" + strings.Join(optional, "\n\t")
		}

		// Sort parameters by location
		actionParams := paramAnalyzer.Params
		leafParams := paramAnalyzer.LeafParams
		var pathParamNames []string
		var queryParamNames []string
		var payloadParamNames []string
		for _, p := range leafParams {
			n := p.Name
			if isQueryParam(n) {
				queryParamNames = append(queryParamNames, n)
				p.Location = gen.QueryParam
			} else if isPathParam(n, pathPatterns) {
				pathParamNames = append(pathParamNames, n)
				p.Location = gen.PathParam
			} else {
				payloadParamNames = append(payloadParamNames, n)
				p.Location = gen.PayloadParam
			}
		}
		for _, p := range actionParams {
			done := false
			for _, ap := range leafParams {
				if ap == p {
					done = true
					break
				}
			}
			if done {
				continue
			}
			n := p.Name
			if isQueryParam(n) {
				p.Location = gen.QueryParam
			} else if isPathParam(n, pathPatterns) {
				p.Location = gen.PathParam
			} else {
				p.Location = gen.PayloadParam
			}
		}

		// Mix in filters information
		if filters, ok := meth["filters"]; ok {
			var filterParam *gen.ActionParam
			for _, p := range actionParams {
				if p.Name == "filter" {
					filterParam = p
					break
				}
			}
			if filterParam != nil {
				values := sortedKeys(filters.(map[string]interface{}))
				ivalues := make([]interface{}, len(values))
				for i, v := range values {
					ivalues[i] = v
				}
				filterParam.ValidValues = ivalues
			}
		}

		// Record action
		action := gen.Action{
			Name:              actionName,
			MethodName:        inflect.Camelize(actionName),
			Description:       removeBlankLines(description),
			ResourceName:      inflect.Singularize(name),
			PathPatterns:      pathPatterns,
			Params:            actionParams,
			LeafParams:        paramAnalyzer.LeafParams,
			Return:            parseReturn(actionName, name, contentType),
			ReturnLocation:    actionName == "create" && name != "Oauth2",
			PathParamNames:    pathParamNames,
			QueryParamNames:   queryParamNames,
			PayloadParamNames: payloadParamNames,
		}
		actions = append(actions, &action)
	}

	// We're done!
	name = inflect.Singularize(name)
	descriptor.Resources[name] = &gen.Resource{
		Name:        name,
		ClientName:  "API",
		Description: removeBlankLines(description),
		Actions:     actions,
		Attributes:  attributes,
		LocatorFunc: LocatorFunc(attributes, name),
	}
}