Generating Output

HTTP Requests

The request handling lifecycle on Qbix Platform goes through several events, which you can read more about in our Platform Guide on request handling.

The World Wide Web, and its standards, have been designed around fetching resources from a web server using HTTP requests. These requests come with an HTTP verb such as GET, POST, PUT, DELETE etc. and specify a URL to act upon. Qbix routes this URL to an internal URI, which is a structure than includes the fields $module and $action. When rendered to a string, the structure may look like this:

"SomeModule/someAction field1=value1 field2=value2".

Routing and Unrouting

The decoupling of external URLs from internal URIs is to provide flexibility, in case the maintainers of the website need to change something. However, the founders of the web famously believed that cool URIs don’t change. Removing resources from a URI without a 301 redirect can create broken links that annoy visitors as much as dead end roads without signs.

Routes are found under the "Q"/"routes" config, and various plugins and apps can add to it. The routes are traversed in reverse order, with the latest added tried first, but the special "Q"/"routes@start" and "Q"/"routes@end" configs allow plugins and apps to set the priority for some routes over (or under) others. Although formally, JSON objects aren’t supposed to have an order, Qbix takes advantage of the fact that PHP natively has an order to associative arrays and parsed JSON.

Normally, there should be a 1-1 mapping between internal URIs and URLs, but sometimes multiple URLs may route to the same exact URI, and thus render the same or similar output. In this case, when mapping URLs to and from URIs using Q_Uri::fromUrl($url) and $uri->toUrl() the first matching route encountered is used.

On the web, a series of similar web pages can include a meta tag that indicates which URL should be canonical, for search engines to avoid listing duplicates, and other similar purposes. You can easily set meta tags with Q_Response::setMeta($params).

Event Handlers

Qbix Platform developers implement webpages and actions by creating HTTP handlers for various requests. To do that, they simply add event handlers for the appropriately named events, such as

  • "Q/notFound" if there is no route or handler for the internal URI
  • "Q/prepare" giving the app an early hook for the request handling
  • "Q/validate" giving the app a chance to validate the request input
  • "Q/objects" letting the app create internal objects to handle requests
  • "Q/reroute" giving the app a hook to call Q_Dispatcher::forward()
  • "Q/$verb" for handling any HTTP verb other than GET. This is the main time to write to the database and change the state.
  • "Q/analytics" for executing any sorts of analytics. Often involves appending to a log or database.
  • "Q/response" - see more info on producing output

Any event in Qbix Platform can have hooks added before or after it, allowing various plugins and apps to take actions when certain things happen.

Response Extras and Session Extras

Each app or plugin may want to tell the web browser to load some resources, such as css or js files by calling Q_Response::addStylesheet($src) Q_Response::addScript($src). They may do this in an event handler for an action, such as MyApp/somePage/response/content.php. But sometimes, an app or plugin may want to execute these things more globally, such as when other apps or plugins are rendering something. To do this, they can add a hook before or after the events Q/responseExtras and Q/sessionExtras.

Resources on the Web are often stateless, which means that they return the same result regardless of additional information, such as cookies indicating which user is logged in. Even if the information at the URL does gradually change, the same result is given to every user requesting, so it can be cached for a while at multiple layers, such as reverse proxies and CDNs.

In fact, you don’t need to build static sites with tools like Jekyll or Hugo. Instead, you can generate dynamic websites with Qbix Platform, and then cache the output of most popular URLs. Qbix does give you a script, found in scripts/Q/static.php, to generate static HTML pages from your dynamic website, that are compatible with the rest of your site, but you don’t even need it if you engage a CDN provider to cache and serve your content faster to users around the world.

The Q/responseExtras event is for hooks that want to add scripts, stylesheets, and do other things as long as they are stateless, meaning they don’t rely on any information in cookies. For example, you wouldn’t want to call Q_Response::setScriptData() with information specific to the currently logged-in user during this event.

On the other hand, the Q/sessionExtras event is for hooks that want to add user-specific information to the website. This is typically done once in a while, a Single Page Application, when the user makes a request in the context of a session. The subsequent AJAX requests do not trigger this event. Qbix takes care of all this, but if you want to know how it works, look at the function Q_Response::processSessionExtras(). All you have to know is, if your app or plugins wants to send stateful information to the client during an HTTP response, you should add it in a Q/sessionExtras hook.

Optimizing Your Web Apps

A typical end-user or developer would just use the config to enable some plugins that others wrote, which already do everything and have presumably been tested.

After that, they would simply add handlers to their app, such as handlers/MyApp/myAction/response/content.php in order to fill some slots. They’d render templates such as views/MyApp/content/myAction.handlebars or views/MyApp/content/myAction.php using return Q::view($template, $fields). In turn, these could render reusable components with Q::tool($toolName, $options).

The front end code would call Q.page() and Q.Tool.define() to have code to run when a tool or entire page is activated or removed. This code could do requests to various servers (including our own, but also gateways to IPFS, Web3 blockchains, etc.)

Only afterwards, when your site already works, do you want to start taking care of optimizations, such as:

  • Rendering tools on the server side with MyPlugin/something/tool.php, so their HTML comes with the page load
  • Q.getter() and Q.batcher() to batch requests together
  • Caching and Static File Generation, CDNs
  • Bundling web resources with scripts/Q/bundle.php for deployment on iOS, Android via Cordova and other engines

These will be the subject of other articles on this site.

For More Complete Information:

General Resources:

1 Like