Methods

The integration provides some useful common functions and patterns available to be used in applications out the box. Methods are attached to the altitude namespace and provides storefront owners a layer of abstraction away from verbose core commerce functionality and performance uplifts.

Quick method reference

altitude: {
  i18n: (func, ...args) => String;
  commerce: {
    api: async (
      operationFields: { operation: String!, variables: Object! },
      headers: Object!,
      options: { apqEnabled: Boolean }
    ) => Object;
  };
  blog: {
    api: async (
      endpoint: String!,
      operationFields: { operation: String!, variables: Object, cacheKey: Request! || String!, wafBypass: String!, clientSecret: String!, clientId: String!},
      options: { headers: Object }
    ) => Response;
  };
  cache: {
    get: async(cacheKey: String! || Request!, operationName: String) => Response || null;
    set: async(cacheKey: String! || Request!, response: Response!, options: { expiry: Number }) => void;
  }
}

i18n

The i18n method aids with localising copy on site. The function provides flexibility to resolve langauge strings to their values or the object structure to support non-technical stakeholders understand what keys to update.

valueFunc

Type: function() => String
Required: True

An anonymous function that when invoked returns the string that is intended to be evaluated.

args

Type: String
Required: False

Optional argument that will be used to dynamically replace string placeholders in the value of the language string passed, or replace dynamic keys using bracket notation.

Example Use

---
const { altitude: { i18n } } = Astro.locals
const lang = Astro.locals.altitude.rutime.kv.lang

const productTitle = "Vivienne Westwood Logo Ribbed Wool Beanie"
const contentKey = "details"
---
<p>{i18n(() => lang.product.promotionalOffer, productTitle)}</p> // Buy one Vivienne Westwood Logo Ribbed Wool Beanie get one free
<p>{i18n(() => lang.product[contentKey], contentKey)}</p> //lang.product.details will be the string that is now evaluated

Exposing Keys

The keys used for copy on site can be exposed using headers. This will allow the relevant teams to identify the entry on a site and update its value in Content UI on the fly. To expose the keys an additional request header should be added Properties-Preview: SHOW-KEYS

Commerce API

The integration provides out the box commerce api fetching on the server exposing the method as altitude.commerce.api. The method enables applications to configure the operation, variables and headers to retrieve commerce data for a given site or tenant. The endpoint the method will use for these calls will be the commerce.endpoint supplied in an application or tenants build config.

operationFields.operation

Type: String
Required: True

The operation to be passed to the body as the query. Any parsing of the operation should be done at application level ahead of time.

operationFields.variables

Type: Object
Required: True

The variables to be passed as part of the api call. If no variables are required an empty object should be passed.

headers

Type: Object
Required: True

All required headers to be passed as part of the commerce fetch. No headers are defaulted so all should be provided.

options.apqEnabled

Type: Boolean
Required: False
Default: False

This enables Horizons Automatic Persisted Queries feature.

Return value

From version 1.7.0 the api method returns the full response object.

Version <=1.6.X The commerce api method will return an Object containing three values: body, duration, status.

  • body: The response from the api call.
  • duration: The duration of the api call in ms.
  • status: The status code of the response.

Example use

//c/index.astro

const body = await locals.query({
  operation: Schema,
  variables: {
    handle: pathName,
  },
  customHeaders: {
    foo: 'bar',
  },
})
//middleware/index.js
import { print } from 'graphql'

query: async (args) => {
  const { operation, variables = {}, customHeaders = {} } = args

  let query
  if (typeof operation == 'string') {
    query = operation
  } else {
    query = print(operation)
  }

  try {
    const { body, duration, status } = await locals.altitude.commerce.api(
      { operation: query, variables },
      {
        ...customHeaders,
        'Content-Type': 'application/json',
        'User-Agent': request.headers.get('User-Agent'),
        'X-Altitude-Instance': locals.tenantInstance, // application specific header
      },
      {
        apqEnabled: false,
      }
    )
    return body
  } catch (e) {
    console.log(e)
  }
}

Cache API

The cache api can be used to enhance the performance of sites by reducing the number of network calls being made as it reduces load times and avoids repeated API calls, which is especially beneficial for large components which do not change often such as the header and footer. Instead, the response of these calls can be set in cache so future requests can attempt to retrieve the response from cache instead of calling the origin.

Get

cacheKey

Type: String || Request
Required: True

The cache key to be used to get a response from cache. This value must be unique when in a multi tenancy environment and cache keys can be easily created using the helper function altitude.createCacheKey(key: String)

operationName

Type: String
Required: False
Default: ""

The get cache api function logs out the operation name that has receieved a cache hit for observability.

Example Use

let response, cacheKey
if (!import.meta.env.DEV) {
  cacheKey = altitude.createCacheKey(`${horizonEndpoint}/${host}/headerfooter`)
  response = await altitude.cache.get(cacheKey, 'nav')
}

Set

cacheKey

Type: String || Request
Required: True

The cache key to be used to set a response in cache for request lookups. This value must be unique when in a multi tenancy environment and cache keys can be easily created using the helper function altitude.createCacheKey(key: String)

response

Type: Response
Required: True

The response object to be put into cache to be retrieved for future cache lookups.

options.expiry

Type: Number
Required: False
Default: 600

Optional value for how long this response should stay in the cache for in seconds. Defaulted to 600 seconds (10 minutes)

Example Use

if (!response) {
  try {
    response = await Astro.locals.utils.query({
      operation: HeaderFooter,
    })

    if (response.statusText !== 'OK') throw new Error('Error Fetching nav')

    if (!import.meta.env.DEV) {
      await altitude.cache.set(cacheKey, response.clone(), { expiry: 600 })
    }
  } catch (e) {
    console.log(e.message)
  }
}

Performance can be improved by using the cache as it reduces load times and avoids repeated API calls, which is especially beneficial for large components which do not change often such as the header and footer of pages. For example, by using the functions described above to first check the cache, and if its empty, to populate the cache once the data has been fetched:

Blog API

The blog api function is used to fetch blog content from a specified endpoint. The fetch utilises the Cache API to get and set auth tokens which are sent as a header to reduce the amount of calls to auth service.

endpoint

Type: String
Required: True

The endpoint the integration should use to retrieve blog data.

operationFields.operation

Type: String
Required: True

The operation to be passed to the body as the query. Any parsing of the operation should be done at application level ahead of time.

operationFields.variables

Type: Object
Required: False

The variables to be passed as part of the api call.

operationFields.cacheKey

Type: String || Request
Required: True

The cache key to be used to get and set auth tokens from cache. This value must be unique when in a multi tenancy environment and cache keys can be easily created using the helper function altitude.createCacheKey(key: String)

operationFields.wafBypass

Type: String
Required: True

Application specific WAF bypass key, used for auth.

operationFields.clientSecret

Type: String
Required: True

Application specific client secret, used for auth.

operationFields.clientId

Type: String
Required: True

Tenant or Application specific ID, used for auth.

options.headers

Type: Object
Required: False

Any additional headers to be sent as part of the request. Content-Type: application/json and Authorization are currently defaulted.

Example Use

const blogEndpoint =
  Astro.locals?.tenantConfig?.application?.features?.tesseract?.endpoint

let resp
try {
  resp = await altitude.blog.api(blogEndpoint, {
    operation: TesseractHome,
    cacheKey: altitude.createCacheKey(
      `${Astro.locals.tenantConfig.application.horizonEndpoint}/${Astro.locals.host}/blog`
    ),
    wafBypass: import.meta.env.WAF_BYPASS,
    clientSecret: import.meta.env.AUTH_CLIENT_SECRET,
    clientId:import.meta.env.BLOG_CLIENT_ID
  })
} catch (e) {
  console.log(e)
}