How to execute a HttpRequest of type HttpRequestMode.Post

I would like to post a json and I wrote the function:

/**
	 * Post JSON object
	 */
	public func testPostJsonString(var url:String,
		parameters: AnyObject![],
		success: (response:String?) ->(),
		error: (response:Exception?) ->()) ->() {
			
			let content = HttpRequestContent();
			
			let request = HttpRequest( Url(url) );
			request.Mode=HttpRequestMode.Post;
			request.FollowRedirects = true;
			request.Content=content;
			//request.Headers = ["User-Agent" : "swift-test"];
			
			let httpContentResponseBlock: HttpContentResponseBlock<Sugar.Json.JsonDocument!>! = { response in 
				if response.Success {
				
					// Json Object Response
					let jsonObject:Sugar.Json.JsonObject = response.Content.RootObject;
					
					success( jsonObject.ToJson() );
				
				}
				else {
					error(response.Exception);
				}
			}
			Http.ExecuteRequestAsJson( request, httpContentResponseBlock)
			
			
			
	} //testPostJsonString

Looking at the sources - https://github.com/remobjects/sugar/blob/master/Sugar/HTTP.pas
I’m not sure how to pass the Dictionary / String of the contents (supposed to post a JSON / form) using the writable property of type HttpRequestContent.

The typical json to post would be a valid nest json like:

{
  "timestamp" : 1455205092,
  "data" : {
     "name" : "data"
     "type" : "event"
   }
}

Also I see that the headers property is not writable so how to set up custom headers like:

request.Headers = [["User-Agent" : "swift-test"]];

This would help for server that need specific headers like Accept etc.

According to the HTTP.pas:

method ExecuteRequestAsJson(aRequest: not nullable HttpRequest; contentCallback: not nullable HttpContentResponseBlock<JsonDocument>);

I’m doing

 let request = HttpRequest( Url(url) );
request.Mode=HttpRequestMode.Post;
request.FollowRedirects = true;
request.Content=content;
//...

I get an Exception:

Type: NSException Message: An exception of type: NSException occurred: Invalid Cast Exception Detached

when calling

Http.ExecuteRequestAsJson( request, httpContentResponseBlock)

ExecuteRequestAsJson does a get and handles the result as Json. I don’t think we have explicit support for posting Json data yet, you’d have to post it as binary or string for now. I’ll look at expanding the API (iirc there is a basic mechanism for hooking custom data types into the post data, but I’ll need to check, it’s been a while). I’ll also look at the headers and why those aren writable. That sounds like a bug.

Great! Regarding the headers I see that the property is readonly:

property Headers: not nullable Dictionary<String,String> := new Dictionary<String,String>; readonly;

In the meanwhile I can use the HttpRequestMode.Post with String. Where I put the String, and how make the request (which method of Http or HttpRequest instance to use)?

Thank you!

Well, yes. but that applies to assigning a different dictionary to the property (you can’t and should not). it doesn’t mean you can’t change the one that’d there, and add new values to it?

something like

let body = yourJson.ToString()
request.Content = HttpBinaryRequestContent(body, Encoding.UTF8)

right. And then I can use Http.ExecuteRequestAsBinary or even ExecuteRequestAsString?

Yes.

Latest commit adds an overload for HttpBinaryRequestContent that takes a Json. As for which execute request you wanna run, that depends on what kind of data you expect to get back. If you expect back Json as well, use ExecuteRequestAsJson, for example.

Super! Is in in the develop tree already?
So, I have tried the Http.ExecuteRequest plus headers modifications:

                    let body = "name=test&value=pippo"//yourJson.ToString()
			let request = HttpRequest( Url(url) );
			request.Mode=HttpRequestMode.Post;
			request.FollowRedirects = true;
			request.Headers["User-Agent"]="switft-example";
			request.Content = HttpBinaryRequestContent(body, Encoding.UTF8)
			
			Http.ExecuteRequest(request, { response in
				if response.Success {
					response.GetContentAsString(nil) { content in
						if content.Success {
							success( content.Content )
						}
						else {
							error(response.Exception);
						}
					}
				}
			});

The dumped response was - http://www.posttestserver.com/data/2016/02/12/swift-promise/01.37.08192355800

Time: Fri, 12 Feb 16 01:37:08 -0800
Source ip: 89.97.90.230

Headers (Some may be inserted by server)
REQUEST_URI = /post.php?dir=swift-promise
QUERY_STRING = dir=swift-promise
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 59093
REMOTE_ADDR = 89.97.90.230
HTTP_ACCEPT_ENCODING = gzip, deflate
CONTENT_LENGTH = 21
HTTP_ACCEPT_LANGUAGE = it-it
HTTP_USER_AGENT = SampleiOSApp/1.0 CFNetwork/758.2.8 Darwin/15.0.0
HTTP_ACCEPT = */*
HTTP_CONNECTION = close
CONTENT_TYPE = application/x-www-form-urlencoded
HTTP_HOST = posttestserver.com
SSL_TLS_SNI = posttestserver.com
HTTPS = on
UNIQUE_ID = Vr2nxEBaMGUAAE7Xd3AAAAAG
REQUEST_TIME_FLOAT = 1455269828.2091
REQUEST_TIME = 1455269828

Post Params:
key: 'name' value: 'test'
key: 'value' value: 'pippo'
Empty post body.

Upload contains PUT data:
name=test&value=pippo

The request url was on a test server apiEndpoint="https://posttestserver.com/post.php?dir=swift-promise"

It was the right way to modify headers in

request.Headers["User-Agent"]="switft-example";

It seems that the server is not getting the change. Tested on both Fire / Xcode iOS apps.

So looks like it’s all working?

The post is working but the headers are not being modified doing request.Headers["User-Agent"]="switft-example"; (maybe it’s not the right way…)

Ah, ok. i’ll check. this happens on iOS only, or al all platforms?

Looks like indeed the leaders are never being set. Fixing.

@mh I was not able to test on Android. I will try as soon as I have Fire to get back working!

No need to, i don’t think any platform currently sets them… will fix all — retesting with next would be appreciated though.

Absolutely I’m checking that, thank you!

@mh I have updated Sugar to the latest commit 74be2596d003349e5c6b9ee8fe4e58d8e60766a6 and checkout out, it seems the headers are not modified yet:

Time: Mon, 22 Feb 16 07:22:34 -0800
Source ip: 5.90.77.25

Headers (Some may be inserted by server)
REQUEST_URI = /post.php?dir=swift-promise
QUERY_STRING = dir=swift-promise
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 1221
REMOTE_ADDR = 5.90.77.25
HTTP_ACCEPT_ENCODING = gzip, deflate
CONTENT_LENGTH = 21
HTTP_ACCEPT_LANGUAGE = it-it
HTTP_USER_AGENT = iOSSilverSampleApp/1.0 CFNetwork/758.2.8 Darwin/15.0.0
HTTP_ACCEPT = */*
HTTP_CONNECTION = close
CONTENT_TYPE = application/x-www-form-urlencoded
HTTP_HOST = posttestserver.com
SSL_TLS_SNI = posttestserver.com
HTTPS = on
UNIQUE_ID = VssnukBaMGUAAEA1LckAAAAH
REQUEST_TIME_FLOAT = 1456154554.4659
REQUEST_TIME = 1456154554

Post Params:
key: 'name' value: 'test'
key: 'value' value: 'pippo'
Empty post body.

Upload contains PUT data:
name=test&value=pippo

setting

request.Headers["User-Agent"]="switft-example";

Yes, this fix isn’t in yet, sorry. Didn’t get chance to fully do it for all platforms yet.

1 Like

Are you mixing threads here? is this about HTTP Headers or JSON?

:joy: I just wrote a response supposed to be in Sugar.json.JsonObject.getKeys: java.lang.ClassCastException here, don’t tell me why…removing!