Exemple #1
0
func addSwaggerResponse(responses map[string]*SwaggerResponse, errType string, sym string, errComment string) {
	code := rdl.StatusCode(sym)
	var schema *SwaggerType
	if sym != "NO_CONTENT" {
		schema = new(SwaggerType)
		schema.Ref = "#/definitions/" + errType
	}
	description := rdl.StatusMessage(sym)
	if errComment != "" {
		description += " - " + errComment
	}
	responses[code] = &SwaggerResponse{description, schema}
}
Exemple #2
0
func goMethodBody(reg rdl.TypeRegistry, r *rdl.Resource, precise bool) string {
	errorReturn := "return nil, err"
	dataReturn := "return data, nil"
	noContent := r.Expected == "NO_CONTENT" && r.Alternatives == nil
	if noContent {
		errorReturn = "return err"
		dataReturn = "return nil"
	}
	if r.Outputs != nil {
		dret := "return data"
		eret := "return nil"
		for _, o := range r.Outputs {
			dret += ", " + goName(string(o.Name))
			eret += ", \"\""
		}
		dret += ", nil"
		eret += ", err"
		dataReturn = dret
		errorReturn = eret
	}
	headers := map[string]rdl.Identifier{}
	for _, in := range r.Inputs {
		if in.Header != "" {
			headers[in.Header] = in.Name
		}
	}
	s := ""
	httpArg := "url, nil"
	if len(headers) > 0 {
		//not optimal: when the headers are empty ("") they are still included
		httpArg = "url, headers"
		s += "\theaders := map[string]string{\n"
		for k, v := range headers {
			s += fmt.Sprintf("\t\t%q: %s,\n", k, v)
		}
		s += "\t}\n"
	}
	url := explodeURL(reg, r)
	s += "\turl := client.URL + " + url + "\n"
	method := capitalize(strings.ToLower(r.Method))
	assign := ":="
	switch method {
	case "Get", "Delete":
		s += "\tresp, err := client.http" + method + "(" + httpArg + ")\n"
	case "Put", "Post", "Patch":
		bodyParam := "?"
		for _, in := range r.Inputs {
			name := in.Name
			if !in.PathParam && in.QueryParam == "" && in.Header == "" {
				bodyParam = string(name)
				break
			}
		}
		s += "\tcontentBytes, err := json.Marshal(" + bodyParam + ")\n"
		s += "\tif err != nil {\n\t\t" + errorReturn + "\n\t}\n"
		s += "\tresp, err := client.http" + method + "(" + httpArg + ", contentBytes)\n"
		assign = "="
	case "Options":
		bodyParam := "?"
		for _, in := range r.Inputs {
			name := in.Name
			if !in.PathParam && in.QueryParam == "" && in.Header == "" {
				bodyParam = string(name)
				break
			}
		}
		if bodyParam != "?" {
			s += "\tcontentBytes, err := json.Marshal(" + bodyParam + ")\n"
			s += "\tif err != nil {\n\t\t" + errorReturn + "\n\t}\n"
			s += "\tresp, err := client.http" + method + "(" + httpArg + ", contentBytes)\n"
			assign = "="
		} else {
			s += "\tresp, err := client.http" + method + "(" + httpArg + ", nil)\n"
		}
	}
	s += "\tif err != nil {\n\t\t" + errorReturn + "\n\t}\n"
	s += "\tcontentBytes, err " + assign + " ioutil.ReadAll(resp.Body)\n"
	s += "\tresp.Body.Close()\n"
	s += "\tif err != nil {\n\t\t" + errorReturn + "\n\t}\n"
	s += "\tswitch resp.StatusCode {\n"
	//loop for all expected results
	var expected []string
	expected = append(expected, rdl.StatusCode(r.Expected))
	couldBeNoContent := "NO_CONTENT" == r.Expected
	couldBeNotModified := "NOT_MODIFIED" == r.Expected
	for _, e := range r.Alternatives {
		if "NO_CONTENT" == e {
			couldBeNoContent = true
		}
		if "NOT_MODIFIED" == e {
			couldBeNotModified = true
		}
		expected = append(expected, rdl.StatusCode(e))
	}
	s += "\tcase " + strings.Join(expected, ", ") + ":\n"
	if couldBeNoContent || couldBeNotModified {
		if !noContent {
			s += "\t\tvar data *" + string(r.Type) + "\n"
			tmp := ""
			if couldBeNoContent {
				tmp = "204 != resp.StatusCode"
			}
			if couldBeNotModified {
				if tmp != "" {
					tmp += " || "
				}
				tmp += "304 != resp.StatusCode"
			}
			s += "\t\tif " + tmp + " {\n"
			s += "\t\t\terr = json.Unmarshal(contentBytes, &data)\n"
			s += "\t\t\tif err != nil {\n\t\t\t\t" + errorReturn + "\n\t\t\t}\n"
			s += "\t\t}\n"
		}
	} else {
		s += "\t\tvar data *" + string(r.Type) + "\n"
		s += "\t\terr = json.Unmarshal(contentBytes, &data)\n"
		s += "\t\tif err != nil {\n\t\t\t" + errorReturn + "\n\t\t}\n"
	}
	//here, define the output headers
	if r.Outputs != nil {
		for _, o := range r.Outputs {
			otype := goType(reg, o.Type, false, "", "", precise, true)
			header := fmt.Sprintf("resp.Header.Get(rdl.FoldHttpHeaderName(%q))", o.Header)
			if otype != "string" {
				header = otype + "(" + header + ")"
			}
			s += "\t\t" + goName(string(o.Name)) + " := " + header + "\n"
		}
	}
	s += "\t\t" + dataReturn + "\n"
	//end loop
	s += "\tdefault:\n"
	s += "\t\tvar errobj rdl.ResourceError\n"
	s += "\t\tjson.Unmarshal(contentBytes, &errobj)\n"
	s += "\t\tif errobj.Code == 0 {\n"
	s += "\t\t\terrobj.Code = resp.StatusCode\n"
	s += "\t\t}\n"
	s += "\t\tif errobj.Message == \"\" {\n"
	s += "\t\t\terrobj.Message = string(contentBytes)\n"
	s += "\t\t}\n"
	s += "\t\t" + errorReturn + "obj\n"
	s += "\t}"

	return s
}
Exemple #3
0
func goHandlerBody(reg rdl.TypeRegistry, name string, r *rdl.Resource, precise bool, prefixEnums bool) string {
	s := ""
	var fargs []string
	bodyName := ""
	for _, in := range r.Inputs {
		name := "arg" + capitalize(string(in.Name))
		if in.QueryParam != "" {
			qname := in.QueryParam
			if in.Optional || in.Default != nil {
				s += goParamInit(reg, qname, name, in.Type, in.Default, in.Optional, precise, prefixEnums)
			} else {
				log.Println("RDL error: queryparam must either be optional or have a default value")
			}
			fargs = append(fargs, name)
		} else if in.PathParam {
			bt := reg.BaseTypeName(in.Type)
			switch bt {
			case "Enum":
				s += fmt.Sprintf("\t%s := New%s(context.Params[%q])\n", name, in.Type, in.Name)
			case "Int32", "Int64", "Int16", "Int8":
				if precise {
					s += fmt.Sprintf("\t%s := %s(intFromString(context.Params[%q]))\n", name, in.Type, in.Name)
				} else {
					s += fmt.Sprintf("\t%s := intFromString(context.Params[%q])\n", name, in.Name)
				}
			case "Float32", "Float64":
				if precise {
					s += fmt.Sprintf("\t%s := %s(floatFromString(context.Params[%q]))\n", name, in.Type, in.Name)
				} else {
					s += fmt.Sprintf("\t%s := floatFromString(context.Params[%q])\n", name, in.Name)
				}
			default:
				if precise && strings.ToLower(string(in.Type)) != "string" {
					s += fmt.Sprintf("\t%s := %s(context.Params[%q])\n", name, in.Type, in.Name)
				} else {
					s += fmt.Sprintf("\t%s := context.Params[%q]\n", name, in.Name)
				}
			}
			fargs = append(fargs, name)
		} else if in.Header != "" {
			hname := in.Header
			def := ""
			if in.Default != nil {
				switch v := in.Default.(type) {
				case string:
					def = fmt.Sprintf("%q", v)
				default:
					panic(fmt.Sprintf("implement me, default value: %v", in))
				}
				s += "\t" + name + "Optional := " + def + "\n"
				s += fmt.Sprintf("\t%s := rdl.HeaderParam(request, %q, %sOptional)\n", name, hname, name)
			} else if in.Optional {
				s += fmt.Sprintf("\t%s := rdl.OptionalHeaderParam(request, %q)\n", name, hname)
			} else {
				s += fmt.Sprintf("\t%s := rdl.HeaderParam(request, %q, \"\")\n", name, hname)
			}
			fargs = append(fargs, name)
		} else {
			bodyName = name
			s += "\tbody, oserr := ioutil.ReadAll(request.Body)\n"
			s += "\tif oserr != nil {\n"
			s += "\t\trdl.JSONResponse(writer, http.StatusBadRequest, rdl.ResourceError{Code: http.StatusBadRequest, Message: \"Bad request: \" + oserr.Error()})\n"
			s += "\t\treturn\n"
			s += "\t}\n"
			pgtype := goType(reg, in.Type, false, "", "", precise, true)
			s += "\tvar " + bodyName + " " + pgtype + "\n"
			s += "\toserr = json.Unmarshal(body, &" + bodyName + ")\n"
			s += "\tif oserr != nil {\n"
			s += "\t\trdl.JSONResponse(writer, http.StatusBadRequest, rdl.ResourceError{Code: http.StatusBadRequest, Message: \"Bad request: \" + oserr.Error()})\n"
			s += "\t\treturn\n"
			s += "\t}\n"
			fargs = append(fargs, bodyName)
		}
	}
	if r.Auth != nil {
		if r.Auth.Authenticate {
			s += authenticateTemplate
		} else if r.Auth.Action != "" && r.Auth.Resource != "" {
			resource := r.Auth.Resource
			i := strings.Index(resource, "{")
			for i >= 0 {
				j := strings.Index(resource[i:], "}")
				if j < 0 {
					break
				}
				j += i
				val := "string(arg" + capitalize(resource[i+1:j]) + ")"
				resource = resource[0:i] + "\" + " + val + " + \"" + resource[j+1:]
				i = strings.Index(resource, "{")
			}
			resource = "\"" + resource
			if strings.HasSuffix(resource, "+ \"") {
				resource = resource[0 : len(resource)-3]
			} else {
				resource = resource + "\""
			}
			if strings.HasPrefix(resource, "\"\" + ") {
				resource = resource[5:]
			}
			s += fmt.Sprintf(authorizeTemplate, r.Auth.Action, resource)
		} else {
			log.Println("*** Badly formed auth spec in resource input:", r)
		}
	}
	methName, _ := goMethodName(reg, r, precise)
	sargs := ""
	if len(fargs) > 0 {
		sargs = ", " + strings.Join(fargs, ", ")
	}
	outHeaders := ""
	for _, v := range r.Outputs {
		outHeaders += ", " + string(v.Name)
	}
	noContent := r.Expected == "NO_CONTENT" && len(r.Alternatives) == 0
	if noContent {
		s += "\terr" + outHeaders + " := adaptor.impl." + capitalize(methName) + "(context" + sargs + ")\n"
	} else {
		s += "\tdata" + outHeaders + ", err := adaptor.impl." + capitalize(methName) + "(context" + sargs + ")\n"
	}
	s += "\tif err != nil {\n"
	s += "\t\tswitch e := err.(type) {\n"
	s += "\t\tcase *rdl.ResourceError:\n"
	//special case the 304 response, which MUST have an etag in it
	for _, v := range r.Outputs {
		if strings.ToLower(v.Header) == "etag" {
			s += "\t\t\tif e.Code == 304 && " + string(v.Name) + " != \"\" {\n"
			s += "\t\t\t\twriter.Header().Set(\"" + v.Header + "\", " + string(v.Name) + ")\n"
			s += "\t\t\t}\n"
			break
		}
	}

	s += "\t\t\trdl.JSONResponse(writer, e.Code, err)\n"
	s += "\t\tdefault:\n"
	s += "\t\t\trdl.JSONResponse(writer, 500, &rdl.ResourceError{Code: 500, Message: e.Error()})\n"
	s += "\t\t}\n"
	s += "\t} else {\n"
	for _, v := range r.Outputs {
		vname := string(v.Name)
		if v.Optional {
			s += "\t\tif " + vname + " != nil {\n"
			s += "\t\t\twriter.Header().Set(\"" + v.Header + "\", " + vname + ")\n"
			s += "\t\t}\n"
		} else {
			s += "\t\twriter.Header().Set(\"" + v.Header + "\", " + vname + ")\n"
		}
	}
	if noContent { //other non-content responses?
		s += fmt.Sprintf("\t\twriter.WriteHeader(204)\n")
	} else {
		//fixme: handle alternative responses. How deos the handler pass them back?
		s += fmt.Sprintf("\t\trdl.JSONResponse(writer, %s, data)\n", rdl.StatusCode(r.Expected))
	}
	s += "\t}\n"
	return s
}
Exemple #4
0
func formatResource(out io.Writer, registry rdl.TypeRegistry, rez *rdl.Resource) {
	fmt.Fprintf(out, "\n#### %s %s\n", strings.ToUpper(rez.Method), rez.Path)
	if rez.Comment != "" {
		fmt.Fprintf(out, "%s", formatBlock(rez.Comment, 0, 80, ""))
	}
	if len(rez.Inputs) > 0 {
		var rows [][]string
		for _, f := range rez.Inputs {
			fn := string(f.Name)
			ft := annotate(registry, f.Type)
			fs := ""
			if f.PathParam {
				fs = "path"
			} else if f.QueryParam != "" {
				fs = "query: " + f.QueryParam
			} else if f.Header != "" {
				fs = "header: " + f.Header
				//			} else if f.Context != "" {
				//				fs = "context: " + f.Context
			} else {
				fs = "body"
			}
			fo := ""
			if f.Optional {
				fo = "optional"
			}
			if f.Default != nil {
				s := optionalAnyToString(f.Default)
				if fo == "" {
					fo = "default=" + s
				} else {
					fo += ", default=" + s
				}
			}
			if f.Pattern != "" {
				if fo != "" {
					fo += ", "
				}
				fo += "pattern: " + f.Pattern
			}
			if f.Flag {
				if fo != "" {
					fo += ", "
				}
				fo += "flag"
			}
			fc := ""
			if f.Comment != "" {
				fc += f.Comment
			}
			row := []string{fn, ft, fs, fo, fc}
			rows = append(rows, row)
		}
		if rows != nil {
			fmt.Fprintf(out, "\n#### Request parameters:\n\n")
			formatTable(out, []string{"Name", "Type", "Source", "Options", "Description"}, rows)
		}
	}
	if len(rez.Outputs) > 0 {
		var rows [][]string
		for _, f := range rez.Outputs {
			fn := string(f.Name)
			ft := annotate(registry, f.Type)
			fd := "header: " + f.Header
			fo := "false"
			if f.Optional {
				fo = "true"
			}
			fc := ""
			if f.Comment != "" {
				fc = f.Comment
			}
			row := []string{fn, ft, fd, fo, fc}
			rows = append(rows, row)
		}
		if rows != nil {
			fmt.Fprintf(out, "\n#### Response parameters:\n\n")
			formatTable(out, []string{"Name", "Type", "Destination", "Optional", "Description"}, rows)
		}
	}
	fmt.Fprintf(out, "\n#### Responses:\n\n")
	var results [][]string
	if rez.Expected != "OK" {
		e := rez.Expected
		s := ""
		if e != "NO_CONTENT" {
			s = annotate(registry, rez.Type)
		}
		results = append(results, []string{rdl.StatusCode(e) + " " + rdl.StatusMessage(e), s})
	} else {
		results = append(results, []string{"200 " + rdl.StatusMessage("OK"), string(rez.Type)})
	}
	if len(rez.Alternatives) > 0 {
		for _, v := range rez.Alternatives {
			s := ""
			if v != "NO_CONTENT" {
				s = annotate(registry, rez.Type)
			}
			results = append(results, []string{rdl.StatusCode(v) + " " + rdl.StatusMessage(v), s})
		}
	}
	fmt.Fprintf(out, "Expected:\n\n")
	formatTable(out, []string{"Code", "Type"}, results)

	if len(rez.Exceptions) > 0 {
		var rows [][]string
		for ec, edef := range rez.Exceptions {
			etype := edef.Type
			et := annotate(registry, rdl.TypeRef(etype))
			ecomment := edef.Comment
			row := []string{rdl.StatusCode(ec) + " " + rdl.StatusMessage(ec), et, ecomment}
			rows = append(rows, row)
		}
		if rows != nil {
			sort.Sort(byCode(rows))
			fmt.Fprintf(out, "\nException:\n\n")
			formatTable(out, []string{"Code", "Type", "Comment"}, rows)
		}
	}
}