HTTP Serverless Functions | Yext Hitchhikers Platform

Overview

HTTP serverless functions allow you to write API endpoints that are served by the Pages system. Setting up a serverless function is straightforward and allows you to write custom code that executes when your endpoint is hit in the browser or by any HTTP client.

To see an example of a repository with working serverless functions, check out this repo on GitHub.

book
Note
Pages supports HTTP serverless functions and lifecycle functions.

Getting Started

Foldering

All Pages serverless functions live in the top-level functions directory. For a function to be exposed as an HTTP endpoint, you must write a TypeScript file under functions/http.

Here is a simple example, which exposes the following endpoint relative to the base URL of your site: /helloWorld.

functions
└── http
    └── helloWorld.ts

Pages also supports path parameters and deeper directory nesting. The following structure exposes the following endpoints relative to the base URL of your site:

  • /helloWorld
  • /api/helloWorld
  • /api/names/{{name}}

    functions
    └── http
        β”œβ”€β”€ api
        β”‚   β”œβ”€β”€ helloWorld.ts
        β”‚   └── names
        β”‚       └── {{name}}.ts
        └── helloWorld.ts

In the above example, the path parameter name is made available in the TypeScript module {{name}}.ts in the body of the argument to the main function.

book
Note
Routing logic will prioritize exact matches over regex matches in the case where there is a conflict between a named file/directory and a parameterized name.

Function Format

To create an HTTP endpoint, you must declare a default export per file, using the following general syntax:

export default function helloWorld(request) {
  const { pathParams, queryParams, site } = request

  return {
    body: "Hello World",
    headers: null,
    statusCode: 200
  }
}

The default export from each file will be supplied one argument (request, in the example above), which includes any environment and invocation-specific information, and will be executed whenever the endpoint is hit by any HTTP request method (GET, PUT, POST, etc.).

Argument and Return Value Interfaces

Refer to the following argument and return value interfaces for your HTTP functions:

interface functionArgument {
  /** Object containing each query parameter as  */
  queryParams: { [key: string]: string},

  /** Internal ID of the site branch. */
  pathParams: { [key: string]: string},

  /** Site object containing all deploy-related information. */
  site: Site
}

interface Site {
  /** Internal ID of the site branch. */
  branchId: string,

  /** Internal ID of the Yext account. */
  businessId: string,

  /** Display name of the Yext account. */
  businessName: string,

  /** The Git commit hash associated with the deploy. */
  commitHash: string,

  /** The Git commit message associated with the deploy. */
  commitMessage: string,

  /** Internal ID for the deploy. */
  deployId: string,

  /** The "base URL" used for reverse proxying, as specified in serving.json. */
  displayUrlPrefix: string,

  /** Environment in which a request is invoked. */
  invocationContext: 'local' | 'preview' | 'staging' | 'production' | null;

  /** External ID of the Yext account. */
  partnerId: string,

  /** URL of the deploy in the Yext platform. */
  platformUrl: string,

  /** URL of preview domain associated with the deploy. */
  previewDomain: string,

  /** URL of production domain associated with the deploy. */
  productionDomain: string,

  /** Name of the GitHub branch associated with the deploy. */
  repoBranchName: string,

  /** URL of the GitHub branch associated with the site. */
  repoBranchUrl: string,

  /** URL of the GitHub repo associated with the site. */
  repoUrl: string,

  /** Internal ID of the site. */
  siteId: string,

  /** Display name of the site. */
  siteName: string,

  /** URL of staging domain associated with the deploy. */
  stagingDomain: string,

  /** Universe of the Yext account. */
  yextUniverse: "development" | "qa" | "sandbox" | "production" | null;
}

interface returnValue {
  /** HTTP response body (refer to MDN Web Docs). */
  body: string,

  /** HTTP response status code (refer to MDN Web Docs). */
  statusCode: number,

  /** HTTP response headers (refer to MDN Web Docs).  */
  headers: object
}

Supported Web APIs

HTTP functions are executed in a Deno runtime; as such, you will have access to the following Deno web platform APIs in your modules.

Environment Variables

Environment variables can be accessed inside your HTTP functions as long as they are prefixed with YEXT_PUBLIC. Refer to the Environment Variables reference doc for more information.

Local Development

TheΒ Yext CLIΒ allows you to develop your HTTP functions locally from the command line. Note, you must be on Yext CLI version 0.1_336 or higher for HTTP function local development (refer to our installation guide ).

You can test your functions by running:

npm run build:serve

This will trigger a full production build of your site and serve it locally at http://localhost:8000.

book
Note

You must run npm run build:serve in order to test your functions locally. If you make any updates to your functions, you must terminate your local dev server and re-run npm run build:serve.

Support for HTTP function with hot-reloading will be added in a future release.

Deployed Logs

Once you deploy your HTTP functions to production, they will be visible from the β€œFunctions” tab in the deploys UI. This screen displays a functions table, which displays all functions (both lifecycle and HTTP) included under your /functions directory.

Deploy Details screen, functions tab, View Logs button

From the functions table, you can click on the β€œView Logs” button to see all calls to your HTTP functions in real time.

Logs screen for Functions

book
Note
It is possible for brief periods of latency between function invocations and their appearance in the logs table.

Troubleshooting

Endpoint not returning responses:

  1. If your endpoint is returning a success status code, but no information in the request body, check the cache-control headers. You may need to configure appropriate caching behavior (no-cache, no-store, etc.) depending on your use case.
Feedback