Host Layouts, Graphics, and Other Resources in an APL Package
Define a set of reusable layouts, graphics, and other resources as an Alexa Presentation Language (APL) package. Host this package on the internet to use the resources in other APL documents. Packages are useful for sharing common items across multiple APL documents without duplicating your code and for simplifying and reducing the size of the code in your skill responses.
Define the package as an APL document
A package uses the same JSON structure as an APL document. A package can leave out the mainTemplate
property. The package ignores the mainTemplate
property if present. Define the items for the package in the top-level properties:
commands
extensions
graphics
layouts
resources
styles
For example, you could define a set of layouts in the layouts
property, and then use those layouts in other APL documents.
The following example shows a package that defines a layout called CircleWithText
.
{
"type": "APL",
"version": "2024.2",
"import": [
{
"name": "alexa-styles",
"version": "1.6.0"
}
],
"layouts": {
"CircleWithText": {
"parameters": [
{
"name": "backgroundColor",
"default": "green"
},
{
"name": "textToDisplay",
"default": "Set text to show!"
}
],
"items": [
{
"type": "Frame",
"borderRadius": "@shapeCircle",
"width": "300dp",
"height": "300dp",
"backgroundColor": "${backgroundColor}",
"item": {
"type": "Text",
"width": "100%",
"height": "100%",
"padding": "@spacingSmall",
"text": "${textToDisplay}",
"textAlign": "center",
"textAlignVertical": "center"
}
}
]
}
}
}
Import other packages
Your package can import other packages. For example, you can create custom layouts that use the responsive components provided in the alexa-layouts
package. Add the import to the import
array, as you would when using the package in a standard APL document:
{
"import": [
{
"name": "alexa-layouts",
"version": "1.7.0"
}
]
}
The CircleWithText
example shown earlier imports the alexa-styles
package to use the spacing and border radius resources.
For details about how to define imports in the import
array, see APL Import.
Export specific items
Use the export
property to define which items you intend to use in other documents when you import your package. This property is useful when you define a layout using multiple "internal" layouts to make the code more modular, but you intend to use the final "public" version.
Tools such as the authoring tool use the export
property to check a document for errors and present the exported items as available. However, the export
property is informational. An APL document that imports the package can still access all the resources defined in the package, even when not included in export
.
The following example shows a package with two layouts (the layout items
are omitted for brevity):
- The
CircleWithText
layout displays specified text within a circle. - The
ListOfCircles
takes an array of strings and displays a list ofCircleWithText
objects. - The example specifically exports the
ListOfCircles
layout to indicate thatListOfCircles
is the layout to use.
When building a document in the authoring tool, using CircleWithText
directly displays as an error to alert you that it isn't intended for use. However, APL still renders the layout.
{
"type": "APL",
"version": "2024.2",
"import": [
{
"name": "alexa-styles",
"version": "1.6.0"
}
],
"export": {
"layouts": [
{
"name": "ListOfCircles",
"description": "A list of circles; specify the text and background colors."
}
]
},
"layouts": {
"ListOfCircles": {
"parameters": [
{
"name": "textItems",
"type": "array"
},
{
"name": "defaultColor",
"type": "string",
"default": "purple"
}
],
"items": []
},
"CircleWithText": {
"parameters": [
{
"name": "backgroundColor",
"default": "green"
},
{
"name": "textToDisplay",
"default": "Set text to show!"
}
],
"items": []
}
}
}
Host the package
To use the package in other APL documents, you must host the JSON file publicly on the internet. You can use services such as Amazon Web Services (AWS) S3 to host your package. Your hosted package must meet the following requirements:
- The link to the JSON file must be fully public
- Cross-Origin Resource Sharing (CORS) for the host must allow
*.amazon.com
- The JSON file must never expire
Make objects stored in Amazon S3 public
To make the link to your package public in Amazon S3, add a bucket policy to grant access. For details, see Setting permissions for website access.
Alternatively, you can use AWS CloudFront to make your package accessible, but restrict access to the direct S3 URL. See the following AWS resources:
- Getting started with a simple CloudFront distribution
- Restricting access to Amazon S3 content by using an origin access identity (OAI)
Configure an S3 CORS policy
The following CORS policy on an S3 bucket gives Alexa devices access to your package:
[
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*.amazon.com"
],
"ExposeHeaders": []
}
]
For more about configuring CORS for an S3 bucket, see Using cross-origin resource sharing (CORS).
Import your package into your document
To use your external package, import the package. Specify the public URL to the package in the source
property. Set the version
and name
to strings that make sense for your package. These properties are required, but don't need to match the actual content of the package. For convenience, use a consistent naming convention. For example, use the name of your JSON file as the package name.
{
"import": [
{
"name": "circle-list",
"version": "1.0",
"source": "https://d111111abcdef8.cloudfront.net/circle-list.json"
}
]
}
You can import multiple packages. For example, if your document uses layouts from your custom package, as well as responsive components, import both your own package and alexa-layouts
. You can also define conditions on imports to control which packages should be imported.
For details about how to define imports in the import
array, see APL Import.
Package example
The following example shows an external package that defines a graphic imported from Lottie.
The following example shows how you could import this package and then use the graphic within an APL document. The CloudFront URL shown in this example is fictitious.
{
"type": "APL",
"version": "2024.2",
"import": [
{
"name": "my-lottie-graphics",
"version": "1.0",
"source": "https://d111111abcdef8.cloudfront.net/my-lottie-graphics.json"
}
],
"mainTemplate": {
"parameters": [
"payload"
],
"items": {
"type": "VectorGraphic",
"source": "blockTowerAnimation",
"width": "100%",
"height": "100%",
"scale": "best-fit",
"align": "center",
"frame": "${(elapsedTime*0.06)%360}"
}
}
}
Troubleshooting an external package
Issue: 403 Error trying to fetch package
Symptoms
The resources specified in the package aren't accessible to your APL document. The Authoring tool reports the error "Request failed with status code 403"
Try this
This error usually indicates that your link to the package URL isn't publicly accessible. Test the link in a browser and make sure you can see the content of the JSON file.
The steps to make your file publicly available depend on how you're hosting the package. For Amazon S3, consider using CloudFront to provide access to your resources. See the following:
- Getting started with a simple CloudFront distribution
- Restricting access to Amazon S3 content by using an origin access identity (OAI)
Issue: Unable to find resources
Symptoms
The package is publicly available, but the resources specified in the package aren't accessible to your APL document. For example, the authoring tool reports "Unable to find layout <layoutName>."
Try this
Make sure your uploaded package is a valid APL document. The APL document must be the top-level of the file and not within any other properties. Note that the authoring tool export feature saves the document, data sources, and sources in a single JSON file with document
, datasources
, and sources
properties. This format isn't valid as an APL document.
For example, an exported APL document initially looks like the following:
{
"document": {
"type": "APL",
"version": "1.8",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {
"ListOfCircles": {},
"CircleWithText": {}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": []
}
},
"datasources": {},
"sources": {}
}
To make this a valid package, move the object assigned to the document
property to the top level and delete the datasources
and sources
properties:
{
"type": "APL",
"version": "1.8",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {
"ListOfCircles": {},
"CircleWithText": {}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": []
}
}
Try this
Make sure you configured cross-origin resource sharing (CORS) to allow *.amazon.com
.
When using Amazon S3 and Amazon CloudFront, see the following links for information about configuring CORS:
- Using cross-origin resource sharing (CORS)
- Troubleshooting CORS
- How do I resolve the "No 'Access-Control-Allow-Origin' header is present on the requested resource" error from CloudFront?
Related topics
Last updated: Nov 28, 2023