// Call sends the input to the endpoint and returns the result.
Call sends the input to the endpoint and returns the result.
// Call sends the input to the endpoint and returns the result .
func (api *API) Call(method, path string, ctx *Context, input json.RawMessage) (out interface{}, err error) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("API.Call panic: %v\n", r)
			debug.PrintStack()
			out = nil
			err = errors.New("Internal error")
		}
	}()
	if ctx == nil {
		ctx = &Context{}
	}
	endpoint, pathVars := api.MatchEndpoint(method, path)
	if endpoint == nil {
		return nil, ErrorNotFound
	}
	ctx.PathVars = pathVars
	for _, hook := range endpoint.PreRequestHooks {
		originalInput := &EndpointInput{method, path, ctx, input}
		modifiedInput, err := hook(originalInput)
		if err != nil {
			return nil, err
		}
		method = modifiedInput.Method
		path = modifiedInput.Path
		ctx = modifiedInput.Ctx
		input = modifiedInput.Input
	}
	handlerType := reflect.TypeOf(endpoint.Handler)
	if handlerType.Kind() != reflect.Func {
		log.Printf("Bad handler type for %s: %s\n", endpoint.Path, handlerType.Kind())
		return nil, ErrorInternal
	}
	if handlerType.NumIn() > 2 {
		log.Printf("Handler %s takes too many args\n", endpoint.Path)
		return nil, ErrorInternal
	}
	var inputType reflect.Type
	var takesContext, takesCustom, ctxPointer bool
	var ctxIndex, customIndex int
	for i := 0; i < handlerType.NumIn(); i++ {
		inType := handlerType.In(i)
		if inType == reflect.TypeOf(Context{}) {
			takesContext = true
			ctxIndex = i
		} else if inType == reflect.TypeOf(&Context{}) {
			takesContext = true
			ctxPointer = true
			ctxIndex = i
		} else {
			takesCustom = true
			customIndex = i
			inputType = handlerType.In(i)
		}
	}
	handlerValue := reflect.ValueOf(endpoint.Handler)
	var resultValues []reflect.Value
	if takesCustom || takesContext {
		inputList := make([]reflect.Value, handlerType.NumIn())
		if takesContext {
			if ctxPointer {
				inputList[ctxIndex] = reflect.ValueOf(ctx)
			} else {
				inputList[ctxIndex] = reflect.ValueOf(*ctx)
			}
		}
		if takesCustom {
			inputVal := reflect.New(inputType)
			inputInterface := inputVal.Interface()
			err = json.Unmarshal(input, inputInterface)
			if err != nil {
				return nil, err
			}
			directInput := reflect.Indirect(reflect.ValueOf(inputInterface))
			inputList[customIndex] = directInput
		}
		resultValues = handlerValue.Call(inputList)
	} else {
		resultValues = handlerValue.Call(nil)
	}
	if len(resultValues) > 2 {
		log.Printf("Handler %s returned too many values\n", endpoint.Path)
		return nil, ErrorInternal
	}
	if len(resultValues) == 2 {
		out = resultValues[0].Interface()
		if errVal := resultValues[1].Interface(); errVal == nil {
			err = nil
		} else {
			err = errVal.(error)
		}
		return
	}
	if len(resultValues) == 1 {
		retval := resultValues[0].Interface()
		if retval == nil {
			return nil, nil
		}
		returnErr, ok := retval.(error)
		if ok {
			return nil, returnErr
		}
		return retval, nil
	}
	return nil, nil
}
func ( api * API ) Call ( method , path string , ctx * Context , input json . RawMessage ) ( out interface { } , err error ) { defer func ( ) { if r := recover ( ) ; r != nil { log . Printf ( " \n " , r ) debug . PrintStack ( ) out = nil err = errors . New ( " " ) } } ( ) if ctx == nil { ctx = & Context { } } endpoint , pathVars := api . MatchEndpoint ( method , path ) if endpoint == nil { return nil , ErrorNotFound } ctx . PathVars = pathVars for _ , hook := range endpoint . PreRequestHooks { originalInput := & EndpointInput { method , path , ctx , input } modifiedInput , err := hook ( originalInput ) if err != nil { return nil , err } method = modifiedInput . Method path = modifiedInput . Path ctx = modifiedInput . Ctx input = modifiedInput . Input } handlerType := reflect . TypeOf ( endpoint . Handler ) if handlerType . Kind ( ) != reflect . Func { log . Printf ( " \n " , endpoint . Path , handlerType . Kind ( ) ) return nil , ErrorInternal } if handlerType . NumIn ( ) > 2 { log . Printf ( " \n " , endpoint . Path ) return nil , ErrorInternal } var inputType reflect . Type var takesContext , takesCustom , ctxPointer bool var ctxIndex , customIndex int for i := 0 ; i < handlerType . NumIn ( ) ; i ++ { inType := handlerType . In ( i ) if inType == reflect . TypeOf ( Context { } ) { takesContext = true ctxIndex = i } else if inType == reflect . TypeOf ( & Context { } ) { takesContext = true ctxPointer = true ctxIndex = i } else { takesCustom = true customIndex = i inputType = handlerType . In ( i ) } } handlerValue := reflect . ValueOf ( endpoint . Handler ) var resultValues [ ] reflect . Value if takesCustom || takesContext { inputList := make ( [ ] reflect . Value , handlerType . NumIn ( ) ) if takesContext { if ctxPointer { inputList [ ctxIndex ] = reflect . ValueOf ( ctx ) } else { inputList [ ctxIndex ] = reflect . ValueOf ( * ctx ) } } if takesCustom { inputVal := reflect . New ( inputType ) inputInterface := inputVal . Interface ( ) err = json . Unmarshal ( input , inputInterface ) if err != nil { return nil , err } directInput := reflect . Indirect ( reflect . ValueOf ( inputInterface ) ) inputList [ customIndex ] = directInput } resultValues = handlerValue . Call ( inputList ) } else { resultValues = handlerValue . Call ( nil ) } if len ( resultValues ) > 2 { log . Printf ( " \n " , endpoint . Path ) return nil , ErrorInternal } if len ( resultValues ) == 2 { out = resultValues [ 0 ] . Interface ( ) if errVal := resultValues [ 1 ] . Interface ( ) ; errVal == nil { err = nil } else { err = errVal . ( error ) } return } if len ( resultValues ) == 1 { retval := resultValues [ 0 ] . Interface ( ) if retval == nil { return nil , nil } returnErr , ok := retval . ( error ) if ok { return nil , returnErr } return retval , nil } return nil , nil }
Call sends the input to the endpoint and returns the result.
Call sends the input to the endpoint and returns the result .
// Recover from any panics, and return an internal error in that case // Handler functions can take a custom value type and/or a context input // Can return any interface and/or an error // If a value and error are returned, they must be in the order (out, error) // Function may return _either_ an error or a value // If nil, it doesn't matter // Otherwise, check if it can be asserted as an error // Otherwise, assume it's data