Need Help with Tink Surprise / Future

I’m using Ufront, adding an API class which handles the back-end duties of verifying a Google Recaptcha request. In the past I’ve had success doing file operations but now I’m attempting to do an HttpRequest to get JSON data from Google, and I’m having trouble wrapping my head around how to return the result of the ‘verify’ function as a Surprise<String,Error>.

I’ve tried all sorts of combinations based on the Tink Future documentation but I keep returning the wrong combination of Outcome or Future or Surprise. I’m admittedly having a hard time wrapping my head around all the data typing that’s going on. Right now it’s saying about my return line :

src/api/RecaptchaApi.hx:27: characters 2-35 : tink.Surprise<tink.core.Future, Unknown<0>> should be tink.Surprise<String, tink.Error>

Here is what I have right now. Can anyone please help with this?

class RecaptchaApi extends UFApi
{
	public function verify(response:String):Surprise<String, Error> {
		ufTrace("verifying..."+response); //response is the client-side recaptcha result.
		
		var secret = "randomstringfromgoogle";
		var url = "https://www.google.com/recaptcha/api/siteverify";
		
		var theResult = loadFromUrl("https://www.google.com/recaptcha/api/siteverify",response,secret);
		

		theResult.handle(function(data){
			//not used currently, or should I?
		});

		return theResult.asGoodSurprise();
		
	}
	function loadFromUrl(url:String, response:String, secret:String) {
		var h = new haxe.Http(url);
		h.addParameter("response",response);
		h.addParameter("secret",secret);

		return Future.sync(h.request(true));

	}
}

Oh boy, ufront is old ^^

Surprises are not really much of a thing anymore. There’s Promise<T> which is an abstract over Surprise<T, Error> giving you a more convenient behavior and I think ufront should accept it.

Either way, your loadFromUrl function looks pretty odd since h.request(true) returns Void. I’d suggest this:

function request(url:String, ?post:Bool, ?params:Dynamic<String>):Promise<String>
  return Future.async(function (yield) {
    
    var h = new haxe.Http(url);  
    
    if (params != null)
      for (f in Reflect.fields(params))
        h.addParameter(f, Reflect.field(params, f));

    h.onResponse = function (s) yield(Success(s));
    h.onError = function (s) yield(Failure(new Error(504, s)));
    
    h.request(post);
  });

And then:

public function verify(response:String):Surprise<String, Error> //I *think* you can also declare this as `Promise<String>` but you'll have to check
  return request("https://www.google.com/recaptcha/api/siteverify", true, {
    response: response,
    secret: "randomstringfromgoogle"
  });
1 Like

From the boss himself! :wink:
Thanks Juraj—I will let you know how it goes!

So back at this; now the compiler says:

src/api/TestApi.hx:19: lines 19-32 : Warning : Failed to load type tink.CoreApi.Surprise<String, tink.CoreApi.Error>
src/controller/HomeController.hx:211: lines 211-230 : Warning : Failed to load type String
src/api/RecaptchaApi.hx:35: characters 67-82 : Type not found : Promise
src/api/RecaptchaApi.hx:35: characters 67-82 : For optional function argument ‘optionsIn’
src/Server.hx:11: lines 11-42 : Defined in this class

TestApi.hx:19 - Why this? I haven’t changed the code. ( public function getJson(path:String):Surprise<String, Error> {

RecaptchaApi.hx:35 - Not sure why it can’'t find Promise since I have a “using tink.CoreApi” line.

HomeController.hx:211 - This is just bonkers that it can’t load String.

Some bug we found?

Phew. That sounds like perhaps one of ufront’s macros is a bit too magic.

You could try to set the return type of request to Surprise<String, Error> also and see if that works any better. Otherwise, shoot me a mail with the project (my nick at gmail) and I’ll try to punch it until it works ^^

Okay I did that, then I just had to change onResponse to onData and it’s working now! Thanks very much!

	function request(url:String, ?post:Bool, ?params:Dynamic<String>):Surprise<String, Error>
		return Future.async(function (yield) {
			
			var h = new haxe.Http(url);  
			
			if (params != null)
			for (f in Reflect.fields(params))
				h.addParameter(f, Reflect.field(params, f));

			h.onData = function (s) yield(Success(s));
			h.onError = function (s) yield(Failure(new Error(504, s)));
			
			h.request(post);
		});

Question: Is there a term for the technique you are using with “yield”? i.e. where it’s specified as a parameter and then referenced in the two return functions? This intrigued and confused me in the Tink docs example and I want to read up on that some more.

Not that I know of. You will find it in various places though. The most prominent one I’ve come across so far is the constructor for JavaScript promises. It takes a function that gives you a resolve and reject callback to determine the result. In this way the functions that can modify the state of the Future (i.e. yield) or Promise (i.e. reject/resolve) respectively, are constrained in scope.

Thanks again!