Help Form-data API

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Help Form-data API

04 Dec 2021, 12:44

Hello, good morning.
I'd like to assist anyone if you have the proper knowledge.

I'm trying to send an XML file via api, however, it needs it to be sent via post form-data request

I tried to look at several tutorials / libraries in the AHK forum, however, without success of sending.

If I submit this request using Postman, I can do it without any problems, but when Using AHK, I'm not able to succeed.

Here are examples of my attempts.
In case anyone can help me, I'll be grateful.

The idea of the requisition is this:
Image
in the file[] in the value field, the file that will be sent by the script is defined.

Follows prototype for evaluation

Code: Select all

oWhr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
oWhr.Open("POST", "https://sitedoapi.com/requisicao", false)
arquivo:= "C:\2.xml"
boxe := {"boxe/File": false}

objParam := { "file[]": arquivo, "query": boxe}
CreateFormData(postData, hdr_ContentType, objParam)

oWhr.Send(postData)
oWhr.WaitForResponse()

msgbox, % oWhr.ResponseText
The request he returns to me is this:
{"error":{"code":500,"errors":[],"message":"HTTP 415 Unsupported Media Type"}}

If anyone knows, could you give me a light?

Best regards
Thales
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: Help Form-data API

06 Dec 2021, 10:53

we cant guess what you fuctio does, but your arent setting any headers, we dont know if you xml matches the schema, is well formed , etc.
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: Help Form-data API

06 Dec 2021, 11:34

@tank
Thanks for reply

I forgot to say everything about this script, i'm trying to send this XML via api

Code: Select all

<xml>value test</xml>
I'm using createformdata.ahk for this function viewtopic.php?f=6&t=7647


I'm just in trouble sending this request by metaform/formdata

I dont know how i can make this work :(
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: Help Form-data API

06 Dec 2021, 11:49

well that isnt well formed as no type declaration.
https://www.w3resource.com/xml/well-formed.php

and you arent sending any headers.

example
owhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")

it is ecxpplained inthe example

Code: Select all

whr.SetRequestHeader("Content-Type", hdr_ContentType)
whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko") ; probably doesnt matter but better safe than sorry
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: Help Form-data API

06 Dec 2021, 12:07

Hello! @tank
Thanks for the help, but i'm begginer with json language.

I'm trying to send XML via API.

Irf i did it manualy, using the software Postman, i can do it without problem, but when i try to use AHK for this, i cant :\
This form-data dont work with me.


Do you know how i can make that json script for AHK?


I exported this part of Postman, which is what's missing from my script.

Code: Select all

				"body": {
					"mode": "formdata",
					"formdata": [
						{
							"key": "file[]",
							"contentType": "application/xml",
							"type": "file",
							"src": [
								"/C:/DOCUMENT.xml"
							]
						},
						{
							"key": "query",
							"value": "{\"boxe/File\": false}",
							"contentType": "application/json",
							"type": "text"
						}
					]
				}
Do you know how i can convert this part for ahk language?
User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Help Form-data API

06 Dec 2021, 12:38

Does that unnamed api accept json formatted requests? That is more common than XML I thought.
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: Help Form-data API

06 Dec 2021, 12:54

@Chunjee

I dont know if accept, i guess yes, i'm so newbie at this, XD.

I'm trying to get some functions at the forum for make this work
This is my full code

Code: Select all

; Begin the Code
URL := "https://api.onvio.com.br/dominio/invoice/v3/batches"
TokenValidator := "XYZ"
BearerValidator := "BEARER"

SendXMLAPI := ComObjCreate("WinHttp.WinHttpRequest.5.1")
SendXMLAPI.Open("POST", URL , False)
SendXMLAPI.SetRequestHeader("x-integration-key", TokenValidator)
SendXMLAPI.SetRequestHeader("Authorization","Bearer "  BearerValidator)
SendXMLAPI.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko") 
File := "C:\Users\Thales\Desktop\TESTES\1.XML"
boxe := {"boxe/File": false}
objParam := {"file[]": {json: "{'" file "':'application/xml'}"}, "query": {json: "{" boxe ":'application/json'}"}}

CreateFormData(postData, ContentType, objParam)

SendXMLAPI.Send(postData)


Result:= SendXMLAPI.ResponseText
MSGBOX, % Result
My problem is the postData

The result:

Code: Select all

{"error":{"code":500,"errors":[],"message":"HTTP 415 Unsupported Media Type"}}
Look the function of CreateFormData.ahk

Code: Select all

; ===============================================================================

; CreateFormData
; 2020-06-08 - Added a temporary approach to handling the json content-type
;	           example: objParam := { "key": {json: "{'k':'v'}"} }
;
/*
	CreateFormData - Creates "multipart/form-data" for http post
	https://www.autohotkey.com/boards/viewtopic.php?t=7647
	Usage: CreateFormData(ByRef retData, ByRef retHeader, objParam)
		retData   - (out) Data used for HTTP POST.
		retHeader - (out) Content-Type header used for HTTP POST.
		objParam  - (in)  An object defines the form parameters.
		            To specify files, use array as the value. Example:
		                objParam := { "key1": "value1"
		                            , "upload[]": ["1.png", "2.png"] }
	Requirements: BinArr.ahk -- https://gist.github.com/tmplinshi/a97d9a99b9aa5a65fd20
	Version    :      / 2020-06-08 - Added a temporary approach to handling the json content-type
	                                 example: objParam := { "key": {json: "{'k':'v'}"} }
	             1.30 / 2019-01-13 - The file parameters are now placed at the end of the retData
	             1.20 / 2016-06-17 - Added CreateFormData_WinInet(), which can be used for VxE's HTTPRequest().
	             1.10 / 2015-06-23 - Fixed a bug
	             1.00 / 2015-05-14
*/

; Used for WinHttp.WinHttpRequest.5.1, Msxml2.XMLHTTP ...
CreateFormData(ByRef retData, ByRef retHeader, objParam) {
	New CreateFormData(retData, retHeader, objParam)
}

; Used for WinInet
CreateFormData_WinInet(ByRef retData, ByRef retHeader, objParam) {
	New CreateFormData(safeArr, retHeader, objParam)

	size := safeArr.MaxIndex() + 1
	VarSetCapacity(retData, size, 1)
	DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(safeArr), "ptr*", pdata)
	DllCall("RtlMoveMemory", "ptr", &retData, "ptr", pdata, "ptr", size)
	DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(safeArr))
}

Class CreateFormData {

	__New(ByRef retData, ByRef retHeader, objParam) {

		CRLF := "`r`n"

		Boundary := this.RandomBoundary()
		BoundaryLine := "------------------------------" . Boundary

		; Loop input paramters
		binArrs := []
		fileArrs := []
		For k, v in objParam
		{
			If IsObject(v) {
				if v.HasKey("json")
				{
					str := BoundaryLine . CRLF
					     . "Content-Type: application/json" . CRLF . CRLF
					     . v.json . CRLF
					binArrs.Push( BinArr_FromString(str) )
				}
				else
				{
					For i, FileName in v
					{
						str := BoundaryLine . CRLF
						     . "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF
						     . "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF
						fileArrs.Push( BinArr_FromString(str) )
						fileArrs.Push( BinArr_FromFile(FileName) )
						fileArrs.Push( BinArr_FromString(CRLF) )
					}
				}
				
			} Else {
				str := BoundaryLine . CRLF
				     . "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF
				     . v . CRLF
				binArrs.Push( BinArr_FromString(str) )
			}
		}

		binArrs.push( fileArrs* )

		str := BoundaryLine . "--" . CRLF
		binArrs.Push( BinArr_FromString(str) )

		retData := BinArr_Join(binArrs*)
		retHeader := "multipart/form-data; boundary=----------------------------" . Boundary
	}

	RandomBoundary() {
		str := "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z"
		Sort, str, D| Random
		str := StrReplace(str, "|")
		Return SubStr(str, 1, 12)
	}

	MimeType(FileName) {
		n := FileOpen(FileName, "r").ReadUInt()
		Return (n        = 0x474E5089) ? "image/png"
		     : (n        = 0x38464947) ? "image/gif"
		     : (n&0xFFFF = 0x4D42    ) ? "image/bmp"
		     : (n&0xFFFF = 0xD8FF    ) ? "image/jpeg"
		     : (n&0xFFFF = 0x4949    ) ? "image/tiff"
		     : (n&0xFFFF = 0x4D4D    ) ? "image/tiff"
		     : "application/octet-stream"
	}

}

; ===============================================================================
BinArr_FromString(str) {
	oADO := ComObjCreate("ADODB.Stream")

	oADO.Type := 2 ; adTypeText
	oADO.Mode := 3 ; adModeReadWrite
	oADO.Open
	oADO.Charset := "UTF-8"
	oADO.WriteText(str)

	oADO.Position := 0
	oADO.Type := 1 ; adTypeBinary
	oADO.Position := 3 ; Skip UTF-8 BOM
	return oADO.Read, oADO.Close
}

BinArr_FromFile(FileName) {
	oADO := ComObjCreate("ADODB.Stream")

	oADO.Type := 1 ; adTypeBinary
	oADO.Open
	oADO.LoadFromFile(FileName)
	return oADO.Read, oADO.Close
}

BinArr_Join(Arrays*) {
	oADO := ComObjCreate("ADODB.Stream")

	oADO.Type := 1 ; adTypeBinary
	oADO.Mode := 3 ; adModeReadWrite
	oADO.Open
	For i, arr in Arrays
		oADO.Write(arr)
	oADO.Position := 0
	return oADO.Read, oADO.Close
}

BinArr_ToString(BinArr, Encoding := "UTF-8") {
	oADO := ComObjCreate("ADODB.Stream")

	oADO.Type := 1 ; adTypeBinary
	oADO.Mode := 3 ; adModeReadWrite
	oADO.Open
	oADO.Write(BinArr)

	oADO.Position := 0
	oADO.Type := 2 ; adTypeText
	oADO.Charset  := Encoding 
	return oADO.ReadText, oADO.Close
}

BinArr_ToFile(BinArr, FileName) {
	oADO := ComObjCreate("ADODB.Stream")

	oADO.Type := 1 ; adTypeBinary
	oADO.Open
	oADO.Write(BinArr)
	oADO.SaveToFile(FileName, 2)
	oADO.Close
}

; ==================================================================================
; by Coco, https://www.autohotkey.com/boards/viewtopic.php?t=627
Jxon_Load(ByRef src, args*)
{
	static q := Chr(34)

	key := "", is_key := false
	stack := [ tree := [] ]
	is_arr := { (tree): 1 }
	next := q . "{[01234567890-tfn"
	pos := 0
	while ( (ch := SubStr(src, ++pos, 1)) != "" )
	{
		if InStr(" `t`n`r", ch)
			continue
		if !InStr(next, ch, true)
		{
			ln := ObjLength(StrSplit(SubStr(src, 1, pos), "`n"))
			col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))

			msg := Format("{}: line {} col {} (char {})"
			,   (next == "")      ? ["Extra data", ch := SubStr(src, pos)][1]
			  : (next == "'")     ? "Unterminated string starting at"
			  : (next == "\")     ? "Invalid \escape"
			  : (next == ":")     ? "Expecting ':' delimiter"
			  : (next == q)       ? "Expecting object key enclosed in double quotes"
			  : (next == q . "}") ? "Expecting object key enclosed in double quotes or object closing '}'"
			  : (next == ",}")    ? "Expecting ',' delimiter or object closing '}'"
			  : (next == ",]")    ? "Expecting ',' delimiter or array closing ']'"
			  : [ "Expecting JSON value(string, number, [true, false, null], object or array)"
			    , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
			, ln, col, pos)

			throw Exception(msg, -1, ch)
		}

		is_array := is_arr[obj := stack[1]]

		if i := InStr("{[", ch)
		{
			val := (proto := args[i]) ? new proto : {}
			is_array? ObjPush(obj, val) : obj[key] := val
			ObjInsertAt(stack, 1, val)
			
			is_arr[val] := !(is_key := ch == "{")
			next := q . (is_key ? "}" : "{[]0123456789-tfn")
		}

		else if InStr("}]", ch)
		{
			ObjRemoveAt(stack, 1)
			next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}"
		}

		else if InStr(",:", ch)
		{
			is_key := (!is_array && ch == ",")
			next := is_key ? q : q . "{[0123456789-tfn"
		}

		else ; string | number | true | false | null
		{
			if (ch == q) ; string
			{
				i := pos
				while i := InStr(src, q,, i+1)
				{
					val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
					static end := A_AhkVersion<"2" ? 0 : -1
					if (SubStr(val, end) != "\")
						break
				}
				if !i ? (pos--, next := "'") : 0
					continue

				pos := i ; update pos

				  val := StrReplace(val,    "\/",  "/")
				, val := StrReplace(val, "\" . q,    q)
				, val := StrReplace(val,    "\b", "`b")
				, val := StrReplace(val,    "\f", "`f")
				, val := StrReplace(val,    "\n", "`n")
				, val := StrReplace(val,    "\r", "`r")
				, val := StrReplace(val,    "\t", "`t")

				i := 0
				while i := InStr(val, "\",, i+1)
				{
					if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
						continue 2

					; \uXXXX - JSON unicode escape sequence
					xxxx := Abs("0x" . SubStr(val, i+2, 4))
					if (A_IsUnicode || xxxx < 0x100)
						val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
				}

				if is_key
				{
					key := val, next := ":"
					continue
				}
			}

			else ; number | true | false | null
			{
				val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
			
			; For numerical values, numerify integers and keep floats as is.
			; I'm not yet sure if I should numerify floats in v2.0-a ...
				static number := "number", integer := "integer"
				if val is %number%
				{
					if val is %integer%
						val += 0
				}
			; in v1.1, true,false,A_PtrSize,A_IsUnicode,A_Index,A_EventInfo,
			; SOMETIMES return strings due to certain optimizations. Since it
			; is just 'SOMETIMES', numerify to be consistent w/ v2.0-a
				else if (val == "true" || val == "false")
					val := %val% + 0
			; AHK_H has built-in null, can't do 'val := %value%' where value == "null"
			; as it would raise an exception in AHK_H(overriding built-in var)
				else if (val == "null")
					val := ""
			; any other values are invalid, continue to trigger error
				else if (pos--, next := "#")
					continue
				
				pos += i-1
			}
			
			is_array? ObjPush(obj, val) : obj[key] := val
			next := obj==tree ? "" : is_array ? ",]" : ",}"
		}
	}

	return tree[1]
}

Jxon_Dump(obj, indent:="", lvl:=1)
{
	static q := Chr(34)

	if IsObject(obj)
	{
		static Type := Func("Type")
		if Type ? (Type.Call(obj) != "Object") : (ObjGetCapacity(obj) == "")
			throw Exception("Object type not supported.", -1, Format("<Object at 0x{:p}>", &obj))

		is_array := 0
		for k in obj
			is_array := k == A_Index
		until !is_array

		static integer := "integer"
		if indent is %integer%
		{
			if (indent < 0)
				throw Exception("Indent parameter must be a postive integer.", -1, indent)
			spaces := indent, indent := ""
			Loop % spaces
				indent .= " "
		}
		indt := ""
		Loop, % indent ? lvl : 0
			indt .= indent

		lvl += 1, out := "" ; Make #Warn happy
		for k, v in obj
		{
			if IsObject(k) || (k == "")
				throw Exception("Invalid object key.", -1, k ? Format("<Object at 0x{:p}>", &obj) : "<blank>")
			
			if !is_array
				out .= ( ObjGetCapacity([k], 1) ? Jxon_Dump(k) : q . k . q ) ;// key
				    .  ( indent ? ": " : ":" ) ; token + padding
			out .= Jxon_Dump(v, indent, lvl) ; value
			    .  ( indent ? ",`n" . indt : "," ) ; token + indent
		}

		if (out != "")
		{
			out := Trim(out, ",`n" . indent)
			if (indent != "")
				out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent)+1)
		}
		
		return is_array ? "[" . out . "]" : "{" . out . "}"
	}

	; Number
	else if (ObjGetCapacity([obj], 1) == "")
		return obj

	; String (null -> not supported by AHK)
	if (obj != "")
	{
		  obj := StrReplace(obj,  "\",    "\\")
		, obj := StrReplace(obj,  "/",    "\/")
		, obj := StrReplace(obj,    q, "\" . q)
		, obj := StrReplace(obj, "`b",    "\b")
		, obj := StrReplace(obj, "`f",    "\f")
		, obj := StrReplace(obj, "`n",    "\n")
		, obj := StrReplace(obj, "`r",    "\r")
		, obj := StrReplace(obj, "`t",    "\t")

		static needle := (A_AhkVersion<"2" ? "O)" : "") . "[^\x20-\x7e]"
		while RegExMatch(obj, needle, m)
			obj := StrReplace(obj, m[0], Format("\u{:04X}", Ord(m[0])))
	}
	
	return q . obj . q
}
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: Help Form-data API

06 Dec 2021, 13:25

in general xml and json are not interchangable. you are going to have to send your data in the format expected.
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: Help Form-data API

06 Dec 2021, 13:30

without seeing raw request i may not be able to guess what does and doesnt work

the request itself is a json so your content type headee needs to match that.
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: Help Form-data API

06 Dec 2021, 14:27

@tank

Do you know if AHK has any kind of COMOBJECT for POST API FORM DATA with XML files?

Thanks!
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: Help Form-data API

06 Dec 2021, 15:05

you are very confused. this has nothing to do with ahk and everything to do with what the server will accept. you seem unwilling/unable to accept that you cant just send whatever you want and expect it to work
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Help Form-data API

06 Dec 2021, 19:12

Uhh best I can tell that API does accept json requests; it responds with json btw. But it also requires OAuth to authenticate which I don't think is very easy with ahk.

I could be wrong on all of that.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: CaseyMoon, Google [Bot], imstupidpleshelp, Rohwedder, ShatterCoder and 175 guests