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": "2022.2",
  "import": [
    {
      "name": "alexa-styles",
      "version": "1.4.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.5.0"
    }
  ]
}

The CircleWithText example shown earlier imports the alexa-styles package to use the spacing and border radius resources.

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 of CircleWithText objects.
  • The example specifically exports the ListOfCircles layout to indicate that ListOfCircles 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": "2022.2",
  "import": [
    {
      "name": "alexa-styles",
      "version": "1.4.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:

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.

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": "2022.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:

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: