diff --git a/tutorials/fetch.md b/tutorials/fetch.md index a2485fd..7fcb800 100644 --- a/tutorials/fetch.md +++ b/tutorials/fetch.md @@ -1,8 +1,107 @@ -# Making Web Requests +# The new web request API (web.hpp) + +> :warning: This is the documentation for the new web API. We have left the old documentation at the bottom of the page, for the time being Making web requests in C++ sucks, and GD doesn't really help with it. Cocos2d has the `CCHTTPRequest` class, which GD uses to make its web requests, but it's a complicated mess to try to get working and it's not really ergonomical. -Luckily, Geode come to the rescue with the `geode::utils::web` namespace, which contains functions resembling a familiar web API: **fetch**. Geode has two types of web requests: **synchronous** and **asynchronous**. +To fix this, Geode has the `WebRequest` API, which is much more versatile. All web requests are **asynchronous**, so they run on a separate thread. + +Under the hood, the `WebRequests` API uses [Tasks](/tutorials/tasks), so make sure you have read that guide before going into this one. + +## Creating a web request + +Creating a web request is as simple as creating a new `WebRequest` object, and setting some params on it. + +```cpp +#include + +web::WebRequest req = web::WebRequest(); + +// Let's add some query params +req.param("one", "two"); +req.param("three", "four"); + +// Maybe set our UserAgent? +req.userAgent("Geode Web Request!"); + +// For POST / PUT requests, we should probably send a body. Choose whichever suits your needs + +// Byte vector (std::vector) +req.body({ 0x23, 0x24, 0x25 }); +// Strings +req.bodyString("Hello, server!"); +// JSON (uses any matjson::Value) +// Note that you should probably have some actual data in your json +auto myjson = matjson::Value(); +req.json(myjson); + +// Let's set some headers, shall we? +req.header("Content-Type", "application/json"); + +// Set a timeout for the request, in seconds +req.timeout(30); +``` + +There are more functions, regarding certificate verification, proxy settings. You can find more info about them by looking through the headers! + +Now, let's send out request. The API has specific methods for POST, GET, PUT, PATCH. If you want to send a different method, you can use `.send()`. Calling these functions will return a **WebTask**, which is just an alias for `Task`. + +```cpp +// We're still using the same 'req' object from the codeblock above... + +std::string url = "https://example.org"; + +// Let's do a POST request +auto task = req.post(url); +``` + +## Getting the response from our request + +If you remember the [Tasks](/tutorials/tasks) tutorial, you probably also remember that Tasks have to listened to using the [Events](/tutorials/events) system. We can create an `EventListener` for our request and use it to get our response. + +```cpp +class MyCoolClass { + EventListener m_listener; +}; + +// Continuing our code from above... + +m_listener.bind([] (web::WebTask::Event* e) { + if (web::WebResponse* value = e->getValue()) { + // The request finished! + } else if (web::WebProgress* progress = e->getProgress()) { + // The request is still in progress... + } else if (e->isCancelled()) { + // Our request was cancelled + } +}); +m_listener.setFilter(task); +``` + +> :warning: Note that if the task itself goes out of scope, then the request will cancel. If the listener goes out of scope, then the callback will never be called, hence if you want to replace your request, you should cancel the current one, and call setFilter() on the listener instead of creating a new one. + +Once we receive our response, we can check multiple things on it! You can see the list of everything you can do with intellisense, or by checking the headers. + +```cpp +// Check if the response status code is 2xx +res->ok(); +// Get the actual status code +res->code(); +// Get a specific header +res->header("Content-Type"); +// Get all headers +res->headers(); +// Get the response body as bytes +res->data(); +// Get the response body as a string +res->string(); +// Get the response body as matjson::Value (json) +res->json(); +``` + +## The old web APIs + +The old web APIs were deprecated as of **v3.0.0-alpha.1**, you can still find them on older versions of Geode. They contains functions resembling a familiar web API: **fetch**. Geode has two types of web requests: **synchronous** and **asynchronous**. ## Synchronous requests diff --git a/tutorials/tasks.md b/tutorials/tasks.md index b28828f..b44b1f5 100644 --- a/tutorials/tasks.md +++ b/tutorials/tasks.md @@ -134,6 +134,10 @@ m_taskListener.setFilter(calculation()); > :warning: `setFilter` should always be called after `bind` +## Lifetime of a Task + +> :warning: The Task lives as long as the handle (the Task object) is not destroyed. If the handle is destroyed, then the task will be marked as **cancelled**. At the same time, you should also not destroy **the listener** while the request is running. Since all callbacks run on the next frame (on the main thread), then if the listener is destroyed before that, **the callback will never be called**. + ## Other ways of creating Tasks There are other ways to create Tasks. We will go summarily through them, you can find out more info about them by **reading the header file**.