Пример #1
0
// finalizeResource makes the final pass at the resource DSL. This is needed so that the order
// of DSL function calls is irrelevant. For example a resource response may be defined after an
// action refers to it.
func finalizeResource(r *design.ResourceDefinition) {
	r.IterateActions(func(a *design.ActionDefinition) error {
		// 1. Merge response definitions
		for name, resp := range a.Responses {
			if pr, ok := a.Parent.Responses[name]; ok {
				resp.Merge(pr)
			}
			if ar, ok := design.Design.Responses[name]; ok {
				resp.Merge(ar)
			}
			if dr, ok := design.Design.DefaultResponses[name]; ok {
				resp.Merge(dr)
			}
		}
		// 2. Create implicit action parameters for path wildcards that dont' have one
		for _, r := range a.Routes {
			design.Design.IterateVersions(func(ver *design.APIVersionDefinition) error {
				wcs := design.ExtractWildcards(r.FullPath(ver))
				for _, wc := range wcs {
					found := false
					var o design.Object
					if all := a.AllParams(); all != nil {
						o = all.Type.ToObject()
					} else {
						o = design.Object{}
						a.Params = &design.AttributeDefinition{Type: o}
					}
					for n := range o {
						if n == wc {
							found = true
							break
						}
					}
					if !found {
						o[wc] = &design.AttributeDefinition{Type: design.String}
					}
				}
				return nil
			})
		}
		// 3. Compute QueryParams from Params
		if params := a.Params; params != nil {
			queryParams := params.Dup()
			design.Design.IterateVersions(func(ver *design.APIVersionDefinition) error {
				for _, route := range a.Routes {
					pnames := route.Params(ver)
					for _, pname := range pnames {
						delete(queryParams.Type.ToObject(), pname)
					}
				}
				return nil
			})
			// (note: we may end up with required attribute names that don't correspond
			// to actual attributes cos' we just deleted them but that's probably OK.)
			a.QueryParams = queryParams
		}
		return nil
	})
}
Пример #2
0
// finalizeResource makes the final pass at the resource DSL. This is needed so that the order
// of DSL function calls is irrelevant. For example a resource response may be defined after an
// action refers to it.
func finalizeResource(r *design.ResourceDefinition) {
	r.IterateActions(func(a *design.ActionDefinition) error {
		// 1. Merge response definitions
		for name, resp := range a.Responses {
			if pr, ok := a.Parent.Responses[name]; ok {
				resp.Merge(pr)
			}
			if ar, ok := design.Design.Responses[name]; ok {
				resp.Merge(ar)
			}
			if dr, ok := design.Design.DefaultResponses[name]; ok {
				resp.Merge(dr)
			}
		}
		// 2. Create implicit action parameters for path wildcards that dont' have one
		for _, r := range a.Routes {
			wcs := design.ExtractWildcards(r.FullPath())
			for _, wc := range wcs {
				found := false
				var o design.Object
				if a.Params != nil {
					o = a.Params.Type.ToObject()
				} else {
					o = design.Object{}
					a.Params = &design.AttributeDefinition{Type: o}
				}
				for n := range o {
					if n == wc {
						found = true
						break
					}
				}
				if !found {
					o[wc] = &design.AttributeDefinition{Type: design.String}
				}
			}
		}
		return nil
	})
}
Пример #3
0
			}
			route := design.RouteDefinition{
				Verb: "GET",
				Path: "/:id",
			}
			at := design.AttributeDefinition{
				Type: design.String,
			}
			ut := design.UserTypeDefinition{
				AttributeDefinition: &at,
				TypeName:            "id",
			}
			res := design.ResourceDefinition{
				Name:                "Widget",
				BasePath:            "/widgets",
				Description:         "Widgetty",
				MediaType:           "vnd.rightscale.codegen.test.widgets",
				CanonicalActionName: "get",
			}
			get := design.ActionDefinition{
				Name:        "get",
				Description: "get widgets",
				Parent:      &res,
				Routes:      []*design.RouteDefinition{&route},
				Responses:   map[string]*design.ResponseDefinition{"ok": &resp},
				Params:      &params,
			}
			res.Actions = map[string]*design.ActionDefinition{"get": &get}
			mt := design.MediaTypeDefinition{
				UserTypeDefinition: &ut,
				Identifier:         "vnd.rightscale.codegen.test.widgets",
Пример #4
0
// GenerateResourceDefinition produces the JSON schema corresponding to the given API resource.
// It stores the results in cachedSchema.
func GenerateResourceDefinition(api *design.APIDefinition, r *design.ResourceDefinition) {
	s := NewJSONSchema()
	s.Description = r.Description
	s.Type = JSONObject
	s.Title = r.Name
	Definitions[r.Name] = s
	if mt, ok := api.MediaTypes[r.MediaType]; ok {
		buildMediaTypeSchema(api, mt, s)
	}
	for _, a := range r.Actions {
		var requestSchema *JSONSchema
		if a.Payload != nil {
			requestSchema = TypeSchema(api, a.Payload)
			requestSchema.Description = a.Name + " payload"
		}
		if a.Params != nil {
			params := a.Params.Dup()
			// We don't want to keep the path params, these are defined inline in the href
			for _, r := range a.Routes {
				for _, p := range r.Params() {
					delete(params.Type.ToObject(), p)
				}
			}
		}
		var targetSchema *JSONSchema
		var identifier string
		for _, resp := range a.Responses {
			if mt, ok := api.MediaTypes[resp.MediaType]; ok {
				if identifier == "" {
					identifier = mt.Identifier
				} else {
					identifier = ""
				}
				if targetSchema == nil {
					targetSchema = TypeSchema(api, mt)
				} else if targetSchema.AnyOf == nil {
					firstSchema := targetSchema
					targetSchema = NewJSONSchema()
					targetSchema.AnyOf = []*JSONSchema{firstSchema, TypeSchema(api, mt)}
				} else {
					targetSchema.AnyOf = append(targetSchema.AnyOf, TypeSchema(api, mt))
				}
			}
		}
		for i, r := range a.Routes {
			link := JSONLink{
				Title:        a.Name,
				Rel:          a.Name,
				Href:         toSchemaHref(api, r),
				Method:       r.Verb,
				Schema:       requestSchema,
				TargetSchema: targetSchema,
				MediaType:    identifier,
			}
			if i == 0 {
				if ca := a.Parent.CanonicalAction(); ca != nil {
					if ca.Name == a.Name {
						link.Rel = "self"
					}
				}
			}
			s.Links = append(s.Links, &link)
		}
	}
}