Skip to content

Commit

Permalink
docs(general): Improvements to asynchronous HTTP function pages
Browse files Browse the repository at this point in the history
#154

* HTTP Functions page:
  * Added a short introduction about HTTP, including basic terminology
  * Added request functions and notes on URL format
  * Added basic request example
* http_request:
  * Clarified parameter descriptions
  * Removed real data type of body parameter
* Async callback:
  * Moved to RH "note" snippet and inserted on function pages
  * Clarified variables
* Code examples: changed most ds_map_* function calls to DS map accessors
  • Loading branch information
YYBartT committed Oct 3, 2024
1 parent cbfbbb7 commit 0c6616f
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,70 @@
<body>
<!--<div class="body-scroll" style="top: 150px;">-->
<h1><span data-field="title" data-format="default">HTTP</span></h1>
<p>This section lists the different Asynchronous HTTP functions available in <span data-keyref="GameMaker Name">GameMaker</span>. These functions will generate an <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Asynchronous HTTP Event</a> in all instances that have it:</p>
<p>This section lists the different Asynchronous HTTP functions available in <span data-keyref="GameMaker Name">GameMaker</span>.</p>
<p>HTTP stands for <a href="https://en.wikipedia.org/wiki/HTTP">Hypertext Transfer Protocol</a>, which is a protocol for communication on the World Wide Web. It is used when you browse the internet using a web browser, download files, log in to a website, interact with RESTful APIs, ... It has a variant named HTTPS (S indicating &quot;Secure&quot;).</p>
<p>HTTP <em>requests</em> are sent to a web server, which replies by sending back a <em>response</em>. A request uses one of several <em>methods</em>, of which GET and POST are the most common ones. Both the request and response may contain headers (a collection of key-value pairs) and a request body (the actual data to send). The response contains a status code indicating the status and can contain data (e.g. file contents).</p>
<p><span data-keyref="GameMaker Name">GameMaker</span> lets you create and send HTTP requests using the functions on this page. The response is returned in an <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Asynchronous HTTP Event</a> in all instances that have it.</p>
<h2 id="request_functions">Request Functions</h2>
<p>The most general function is <span class="inline3_func"><a data-xref="{title}" href="http_request.htm">http_request</a></span>, which allows you to specify any request method as well as headers and data.</p>
<p>The other functions can be used for more specific requests:</p>
<ul class="colour">
<li><a data-xref="{title}" href="http_request.htm">http_request</a></li>
<li><a data-xref="{title}" href="http_get.htm">http_get</a></li>
<li><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></li>
<li><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_get.htm">http_get</a></span> for a GET request</li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></span> to download a file using GET</li>
<li><span class="inline3_func"><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></span> to make a HTTP request using POST</li>
</ul>
<h3 id="urls">URLs</h3>
<p>All request functions take a URL. The URL string: </p>
<ul class="colour">
<li>must include the protocol, e.g. <span class="inline2">&quot;http://www.google.com&quot;</span> or <span class="inline2">&quot;https://www.google.com&quot;</span>.</li>
<li>can contain an IP address, e.g. <span class="inline2">&quot;http://1.1.1.1&quot;</span>.</li>
<li>can contain <a href="https://en.wikipedia.org/wiki/Query_string">query parameters</a>, e.g. <span class="inline2">&quot;http://www.example.com/examples?example_id={id}&quot;</span>.</li>
</ul>
<p>Note that: </p>
<h2 id="making_requests">Making Requests</h2>
<p>Let&#39;s look at how a general HTTP request is handled from start to end:</p>
<p class="code_heading">Mouse Left Pressed Event</p>
<p class="code">var _map_headers = ds_map_create();<br />
request_id = http_request(&quot;http://www.google.com&quot;, &quot;GET&quot;, _map_headers, &quot;&quot;);<br />
ds_map_destroy(_map_headers);</p>
<p class="code_heading">Async - HTTP Event</p>
<p class="code">if (async_load[? &quot;id&quot;] != request_id) { exit; }<br />
<br />
var _status = async_load[? &quot;status&quot;];<br />
if (_status &lt; 0)<br />
{<br />
    // Error occurred<br />
    <br />
    exit;<br />
}<br />
<br />
if (_status == 1)<br />
{<br />
    // Downloading<br />
    <br />
    exit;<br />
}<br />
<br />
if (_status == 0)<br />
{<br />
    // Request completed!<br />
    <br />
    if (async_load[? &quot;http_status&quot;] == 200)<br />
    {<br />
        // Request was succesful<br />
        <br />
    }<br />
}
</p>
<p>In, for example, a Mouse Left Pressed Event the function <span class="inline3_func"><a data-xref="{title}" href="http_request.htm">http_request</a></span> is called. The request uses the <span class="inline2">&quot;GET&quot;</span> method to retrieve a webpage. No headers are passed and the request body is set to an empty string <span class="inline2">&quot;&quot;</span>.</p>
<p>The <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">Async HTTP event</a> is then triggered one or more times. In this event, the <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span>&#39;s <span class="inline2">&quot;id&quot;</span> key is first checked to see if it matches the <span class="inline2">request_id</span> stored earlier. If not, this event is not for the request made earlier and the code is exited. Next, the <span class="inline2">&quot;status&quot;</span> key is checked. This can hold one of three values: </p>
<ul class="colour">
<li>You can use an IP address in the <span class="inline2">url</span> parameter of all these functions, e.g. <span class="inline2">&quot;http://1.1.1.1&quot;</span>.</li>
<li>The URL string must include the protocol, e.g. <span class="inline2">&quot;http://www.google.com&quot;</span> or <span class="inline2">&quot;https://www.google.com&quot;</span>.</li>
<li>&lt; 0 : error</li>
<li>0 : request completed</li>
<li>1 : content is being downloaded</li>
</ul>
<h2>Connection Timeout</h2>
<p>While downloading content, the event will trigger multiple times, during which the <span class="inline2">&quot;status&quot;</span> key will hold the value 1. Finally, it runs a last time and <span class="inline2">async_load[?&quot;status&quot;]</span> will hold 0 or &lt; 0.</p>
<p>The last time the event triggers for this request, the <span class="inline2">&quot;status&quot;</span> key will hold 0. This value indicates the request has completed. The HTTP status is then checked. If it is 200 (indicating &quot;success&quot;), the data can be found in <span class="inline2">async_load[?&quot;result&quot;]</span>.</p>
<h2 id="connection_timeout">Connection Timeout</h2>
<p>The asynchronous HTTP functions send a request to a server, which might take some time to respond. If the server takes too long to respond, the connection may time out. In <span data-keyref="GameMaker Name">GameMaker</span> this happens after <span data-keyref="HTTP_Timeout_Default">60000</span> ms by default.</p>
<p>The following two functions can be used to get and change this value: </p>
<ul class="colour">
Expand All @@ -43,6 +94,24 @@ <h2 id="cross_domain_issues">Cross-Domain Issues</h2>
<li><a data-xref="{title}" href="http_set_request_crossorigin.htm">http_set_request_crossorigin</a></li>
</ul>
<p>In most cases these functions should not need to be used, but if the game is stored on a secured server - where certain assets may require basic authentication to be accessed and are generating security errors when loading - setting the cross-origin type for image requests to <span class="inline2">&quot;use-credentials&quot;</span> may be necessary (as opposed to the default <span class="inline2">&quot;anonymous&quot;</span> setting).</p>
<h2 id="func_ref">Function Reference</h2>
<h3>Requests</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_request.htm">http_request</a></li>
<li><a data-xref="{title}" href="http_get.htm">http_get</a></li>
<li><a data-xref="{title}" href="http_get_file.htm">http_get_file</a></li>
<li><a data-xref="{title}" href="http_post_string.htm">http_post_string</a></li>
</ul>
<h3>Timeouts</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_get_connect_timeout.htm">http_get_connect_timeout</a></li>
<li><a data-xref="{title}" href="http_set_connect_timeout.htm">http_set_connect_timeout</a></li>
</ul>
<h3>Cross-Domain</h3>
<ul class="colour">
<li><a data-xref="{title}" href="http_get_request_crossorigin.htm">http_get_request_crossorigin</a></li>
<li><a data-xref="{title}" href="http_set_request_crossorigin.htm">http_set_request_crossorigin</a></li>
</ul>
<p> </p>
<p> </p>
<div class="footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
<body>
<!--<div class="body-scroll" style="top: 150px;">-->
<h1><span data-field="title" data-format="default">http_get</span></h1>
<p>This function connects to the specified URL in order to retrieve information.</p>
<p>As this is an asynchronous function, <span data-keyref="GameMaker Name">GameMaker</span> will not block while waiting for a reply, but will keep on running unless it gets callback information. This information will be in the form of a string and will trigger an <b>Async HTTP Event</b> in any instance that has one defined in its object events. You should also note that HTTP request parameters (the bits sometimes &quot;tacked on&quot; to the end of a URL when you submit a form on a web page) are perfectly acceptable when using this function, for example:</p>
<p class="code"><span data-field="title" data-format="default">http_get</span>(&quot;http://www.example.com/logon?username={name}&quot;);</p>
<p>will pass the string held in the variable <span class="inline2">name</span> to the server as well as retrieve the data from that URL. So, essentially, any time a simple, short piece of data needs to be passed from the client to the server, this would be a reasonable choice as the function to use.</p>
<p>This function sends a GET request to the specified URL in order to retrieve information.</p>
<p>This is an asynchronous function, so <span data-keyref="GameMaker Name">GameMaker</span> will not block while waiting for a reply, but will keep on running unless it gets callback information. This information will be in the form of a string and will trigger an <b>Async HTTP Event</b> in any instance that has one defined in its object events.</p>
<div data-conref="../../../../assets/snippets/Note_HTTP_Requests_CrossOrigin.hts"> </div>
<h2>Async Callback</h2>
<p>This function will generate multiple &quot;callbacks&quot; which are picked up by any <a href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">HTTP Events</a>. These will generate a <span data-keyref="Type_ID_DS_Map"><a href="../../Data_Structures/DS_Maps/ds_map_create.htm" target="_blank">DS Map</a></span> (more commonly known as a &quot;dictionary&quot;) that is exclusive to this event and is stored in the special variable <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span>. This DS map will contain different values depending on whether there is data being returned or not. For example, if you have requested a file, the event will trigger multiple times as each packet of data is received so that you can show a progress bar, for example.</p>
<div data-conref="../../../../assets/snippets/Note_HTTP_async_load_Contents.hts"> </div>
<p> </p>
Expand All @@ -35,25 +34,25 @@ <h4>Syntax:</h4>
<tr>
<td>url</td>
<td><span data-keyref="Type_String"><a href="../../../GML_Overview/Data_Types.htm" target="_blank">String</a></span></td>
<td>The web address of the server that you wish to get information from</td>
<td>The web address of the server that you wish to get information from. See <a data-xref="{text}" href="HTTP.htm#urls">URLs</a></td>
</tr>
</tbody>
</table>
<p> </p>
<h4>Returns:</h4>
<p class="code"><span data-keyref="Type_ID_Async_Event"><a href="../Asynchronous_Functions.htm" target="_blank">Async Request ID</a></span> (or -1 if something went wrong)</p>
<p> </p>
<h4>Extended Example:</h4>
<p>The <span class="inline3_func"><span data-field="title" data-format="default">http_get</span></span> function can be called from any event, and since it&#39;s asynchronous the callback can be almost instantaneous or could take several seconds. Calling the function is simple and would look something like this:</p>
<p class="code">request_id = http_get(&quot;http://www.MacSweeneyGames.com/logon?username={name}&quot;);</p>
<h4>Example:</h4>
<p>The <span class="inline3_func"><span data-field="title" data-format="default">http_get</span></span> function can be called from any event, and since it&#39;s asynchronous the callback can be almost instantaneous or could take several seconds. Calling the function is simple and looks something like this:</p>
<p class="code">request_id = http_get($&quot;http://www.MacSweeneyGames.com/logon?username={name}&quot;);</p>
<p>The above code will pass the string held in the variable <span class="inline2">name</span> to the given server as well as retrieve the data from that URL, triggering an Async Event which will contain the <span class="inline2"><a data-xref="{title}" href="../../../GML_Overview/Variables/Builtin_Global_Variables/async_load.htm">async_load</a></span> DS map (the <span class="inline2">async_load</span> map index will be stored in the variable <span class="inline2">request_id</span> so you can check for the correct callback). The Async Event triggered would be the <a data-xref="{title}" href="../../../../The_Asset_Editors/Object_Properties/Async_Events/HTTP.htm">HTTP</a> sub-event, and in that event you would have the following:</p>
<p class="code_heading">Async HTTP Event</p>
<p class="code">if (ds_map_find_value(async_load, &quot;id&quot;) == request_id)<br />
<p class="code">if (async_load[? &quot;id&quot;] == request_id)<br />
{<br />
    var _status = async_load[? &quot;status&quot;];<br />
    var _r_str = (_status == 0) ? async_load[? &quot;result&quot;] : &quot;null&quot;;<br />
}</p>
<p>The above code first checks the ID of the async request, then assigns a value to <span class="inline2">_r_str</span> depending on the <span class="inline2">&quot;status&quot;</span> of the callback. If the value is equal to 0 (signalling success), the result from the callback is stored in a variable for future use, otherwise the variable is set to a default value (in this case <span class="inline2">&quot;null&quot;</span>).</p>
<p>The above code first checks the ID of the async request, then assigns a value to <span class="inline2">_r_str</span> depending on the <span class="inline2">&quot;status&quot;</span> of the callback. If the value is equal to 0 (signalling the request completed), the result from the callback is stored in a variable for future use, otherwise the variable is set to a default value (in this case <span class="inline2">&quot;null&quot;</span>).</p>
<p> </p>
<p> </p>
<div class="footer">
Expand Down
Loading

0 comments on commit 0c6616f

Please sign in to comment.