Understanding the Request Context in PocketPages
PocketPages provides a comprehensive request context object that is accessible in every EJS file. This context object contains several useful properties and functions that enable you to manage request data, log information, require private files, and more. This guide will walk you through the key components of the request context and how to use them effectively.
- The Request Context Object
- Key Properties and Functions
- 1.
ctx
- Theecho.HttpContext
- 2.
params
- Routing and Query String Parameters - 3.
log
- Logging Functions - 4.
requirePrivate
- Requiring Private Files - 5.
stringify
- Circular-Safe Stringify Helper - 6.
context
- The Context Object Itself - 7.
asset
- Asset URL Helper - 8.
url
- URL Parsing Function - 9.
env
- Accessing Environment Variables - 10.
data
- Accessing Loaded Data - 11.
meta
- Managing Page Metadata and Global Values
- 1.
- Key Properties and Functions
- How the Context is Available in EJS
- Additional Notes
The Request Context Object
The request context is automatically passed to every EJS template in your PocketPages application. It provides access to various tools and information relevant to the current request, allowing you to dynamically generate content based on the request data.
Key Properties and Functions
1. ctx
- The echo.HttpContext
- Type:
echo.Context
- Description: The
ctx
property gives you direct access to the underlying Echo framework's HTTP context. This allows you to interact with the request and response, including reading headers, managing cookies, and more.
Example Usage:
<h1>Request Method: <%= ctx.method() %></h1>
<p>Request Path: <%= ctx.path() %></p>
2. params
- Routing and Query String Parameters
- Type: Object
- Description: The
params
object contains both routing parameters (derived from placeholder directory and file names) and query string parameters. If a query string parameter has the same name as a route parameter, the query string parameter will override the route parameter. See Accessing Parameters for more details.
Example Usage:
<h1>Product ID: <%= params.productId %></h1>
<p>Sort by: <%= params.sort %></p>
3. log
- Logging Functions
- Type: Object containing
{ dbg, info, warn, error }
- Description: The
log
object provides logging functions corresponding to the$app.logger()
functions. These methods are used for logging debug information, informational messages, warnings, and errors during the request handling process. When PocketBase is run with--dev
mode,dbg
logs will also appear in the console output; otherwise, onlyinfo
,warn
, anderror
will be displayed.
Logging Methods:
log.dbg(...args)
: Debug-level logging. Visible in console output when running in--dev
mode.log.info(...args)
: Informational messages.log.warn(...args)
: Warnings.log.error(...args)
: Error messages.
Example Usage:
<% log.dbg("Product ID:", params.productId); %>
<% log.info("User accessed the product page."); %>
<% log.warn("Deprecated API used."); %>
<% log.error("An error occurred:", error); %>
4. requirePrivate
- Requiring Private Files
- Type: Function
- Description: The
requirePrivate
function allows you to require private files that are not accessible by any route. This is useful for including sensitive configuration files, utilities, or modules that should not be exposed to the public.
Example Usage:
<%
const config = requirePrivate('config');
log.dbg("Config loaded:", config);
%>
See Private Files for more information.
5. stringify
- Circular-Safe Stringify Helper
- Type: Function
- Description: The
stringify
helper is aJSON.stringify
replacement that prevents circular references from causing errors. It is useful when you need to serialize complex objects for logging or debugging.
Example Usage:
<% log.dbg("Request Context:", stringify(context)); %>
6. context
- The Context Object Itself
- Type: Object
- Description: The
context
property refers to the request context object itself. This can be useful if you need to pass the entire context downstream, for example, when making further processing decisions or passing it to other modules.
Example Usage:
<%
function processContext(ctx) {
// Do something with the context
}
processContext(context);
%>
7. asset
- Asset URL Helper
- Type: Function
- Description: The
asset
function is used to wrap asset URLs, appending a cache-busting stamp when$app.isDev() === true
. This is important when you are developing remotely and are behind a CDN like Cloudflare that caches assets. It ensures that you always get the latest version of your assets during development.
Example Usage:
<img src="<%= asset('images/logo.png') %>" alt="Logo">
Development Mode Output:
<img src="images/logo.png?__cache=12885832" alt="Logo" />
Production Mode Output:
<img src="images/logo.png" alt="Logo" />
8. url
- URL Parsing Function
- Type: Function
- Description: The
url
function is used to parse a URL string. It returns an object equivalent to usingnew URL()
in the browser's Web API. This can be helpful for manipulating or inspecting URLs within your EJS templates.
Example Usage:
<%
const parsedUrl = url('https://example.com/path?query=123');
%>
<p>Hostname: <%= parsedUrl.hostname %></p>
<p>Pathname: <%= parsedUrl.pathname %></p>
<p>Search Params: <%= parsedUrl.search %></p>
9. env
- Accessing Environment Variables
- Type: Function
- Description: The
env
function allows you to securely access environment variables within your EJS templates. Environment variables are often used to store secrets such as API keys, database credentials, and other sensitive information that should not be hard-coded into your application.
Example Usage:
<%
const apiKey = env('API_KEY');
log.info('API Key accessed.');
%>
<p>Your API Key is: <%= apiKey %></p>
Note: Be cautious when displaying sensitive information in your templates to avoid exposing secrets.
10. data
- Accessing Loaded Data
- Type: Object
- Description: The
data
property in the request context contains any data that was loaded by the+load.js
file at the current route level. This data is available to your EJS templates and can be used to dynamically generate content based on the request.
Example Usage:
<h1>Product Name: <%= data.product.name %></h1>
<p>Price: $<%= data.product.price %></p>
11. meta
- Managing Page Metadata and Global Values
- Type: Function
- Description: The
meta
function provides a way to get and set metadata and other global values during request processing. While it can be used for any global values, it's most commonly used to manage page metadata like titles, descriptions, and OpenGraph tags.
Function Signature:
meta(key: string): string | undefined
meta(key: string, value: string): string
Usage Patterns:
- Getting a value:
<% const pageTitle = meta('title'); %>
- Setting a value:
<% meta('title', 'Welcome to My Site'); %>
Common Use Cases:
The most common use case for meta
is setting page metadata in your +load.js
files and then using those values in your layout templates. Here's a typical example from a layout file:
<head>
<title><%= meta('title') || 'PocketPages' %></title>
<meta
name="description"
content="<%= meta('description') || 'Server-side pages for PocketBase' %>"
/>
<!-- OpenGraph tags -->
<meta property="og:title" content="<%= meta('title') || 'PocketPages' %>" />
<meta
property="og:description"
content="<%= meta('description') || 'Server-side pages for PocketBase' %>"
/>
<meta
property="og:image"
content="<%= meta('image') || 'https://pocketpages.dev/android-chrome-512x512.png' %>"
/>
<meta
property="og:url"
content="<%= meta('path') ? `https://pocketpages.dev${meta('path')}` : meta('url') || `https://pocketpages.dev${ctx.request().url}` %>"
/>
</head>
Setting Metadata in Load Files:
You can set metadata values in your +load.js
files before the page renders:
export default async ({ meta }) => {
meta('title', 'About Us')
meta('description', 'Learn more about our company and mission')
meta('image', 'https://example.com/about-preview.jpg')
return {
// ... other loaded data
}
}
Additional Use Cases:
While metadata is the primary use case, meta
can be used for any global values that need to be accessed across different parts of your application during a request:
<%
// Set a global theme
meta('theme', 'dark');
// Set the current user's preferred language
meta('language', 'en-US');
// Later, access these values anywhere in your templates
const theme = meta('theme');
const language = meta('language');
%>
Note: Values set using
meta
only persist for the duration of the current request. They do not persist across different requests or between different users.
How the Context is Available in EJS
The request context is injected automatically into every EJS template rendered by PocketPages. This means that whenever you create an EJS file, you can directly access the context and all its properties and functions without any additional setup.
Example: Using the Request Context in an EJS File
Let's put it all together in a practical example:
<% log.dbg("Rendering Product Page"); %>
<h1>Product ID: <%= params.productId %></h1>
<p>Requested by: <%= ctx.request.header('User-Agent') %></p>
<% if (params.sort) { %>
<p>Sorting by: <%= params.sort %></p>
<% } else { %>
<p>No sorting specified.</p>
<% } %>
<%
const config = requirePrivate('config');
log.dbg("Config loaded:", stringify(config));
%>
<%
const logoUrl = asset('images/logo.png');
%>
<img src="<%= logoUrl %>" alt="Logo">
<%
const parsedUrl = url('https://example.com/path?query=123');
%>
<p>Hostname: <%= parsedUrl.hostname %></p>
<p>Pathname: <%= parsedUrl.pathname %></p>
<p>Search Params: <%= parsedUrl.search %></p>
<h2>Full Request Context</h2>
<pre><%= stringify(context) %></pre>
Explanation:
- Logging: Uses the
log
object to output debug information. - Dynamic Content: Utilizes
params
andctx
to display request-specific data. - Asset Management: Uses the
asset
function to include an image with cache-busting in development mode. - URL Parsing: Demonstrates how to parse a URL using the
url
function. - Security: Loads a private configuration file using
requirePrivate
without exposing it to public routes. - Safety: Utilizes
stringify
to safely serialize and display the entire context, including circular references.
Additional Notes
- Environment Variables: Use
env
to access sensitive data like API keys and avoid exposing them in your templates. - Cache Busting: Use the
asset
function to ensure you're always loading the latest version of your assets during development, especially when behind a CDN. - Logging Levels: Use the appropriate logging method (
dbg
,info
,warn
,error
) to categorize your log messages effectively.