Origami Build Service

Components built and delivered

How to use the Build Service

Before an Origami module can be used by a browser it must be built. You can build them yourself using the Origami Build Tools. If you don't want to do this yourself, you can use the Build Service. The Build Service takes Origami module identifiers and returns all of the minified compiled JavaScript and CSS required by browsers.

Quick start

1. Add this snippet in your document to import the grid system and load the FT webfonts:

<link rel="stylesheet"
href="https://www.ft.com/__origami/service/build/v2/bundles/css?modules=o-grid@^4.0.0,o-fonts@^1.4.0" />
<script src="https://www.ft.com/__origami/service/build/v2/bundles/js?modules=o-grid@^4.0.0,o-fonts@^1.4.0" async />

This is all you need for prototyping with the Build Service. To use the Build Service in production you should also include a cuts the mustard test.

2. Load more modules by adding them to the list:

?modules=o-grid@^4.0.0,o-fonts@^1.4.0,o-header@^4.0.0,o-buttons@^3.0.0

How the build service works

The resource compiler operates on the endpoints starting with /v2/bundles. It packages the requested modules (including all their dependencies) using the standard Origami build process, bundles and minifies the result and returns it as an HTTP response. Individual sub-endpoints serve JS and CSS.

Examples of valid resource compilation requests:

/v2/bundles/js?modules={module}@{version},{module}@{version}...
/v2/bundles/js?modules=o-ads@1.2,o-tracking@3,o-cookiewarn@3.3.1
/v2/bundles/css?modules=o-signinstatus@1.7.3,o-fonts,o-grid@3

You should most likely request all the JS modules you want in a single bundle request, and likewise for CSS, and then write them into the <head> or end of the <body> of your HTML document:

<link rel="stylesheet" href="https://www.ft.com/__origami/service/build/v2/bundles/css?modules=o-ft-nav@2.3,o-share@2,colors" />
<script src="https://www.ft.com/__origami/service/build/v2/bundles/js?modules=o-ft-nav@2.3,o-share@2,o-tracking@3.5,o-ads@1.2" />

Dependency conflicts

Where a resource compiler request results in multiple versions of the same module being included, the build service will generate an error page instead of the requested output. The error page includes information about which modules caused the dependency conflict, and which versions of the depended-upon module are in contention. For example:

Cannot complete build: conflicting dependencies exist.

o-colors:
- Required at version 1.7 by o-nav
- Required at version 1.9 by o-cookiewarn

o-typography:
- Required at version 2.7.4 in the URL
- Required at version ~3.2 by o-nav@1.2.3, o-header@3.2.0
- Required at version 4.* by o-signinstatus@2.2.0
			

Note that some dependencies are required by the explicit module list sent to the build server (referred to above as URL) while others are dependencies of those modules.

Dependency conflicts must be resolved by either the product developer requesting a different version of the modules that contain the conflicting dependencies, or by the module developer updating the modules to allow a broader range of versions of the dependency.

Shinkwrapping

Bundle endpoints (beginning /v2/bundles/) support shrinkwrapping their output. If the module list in your bundle request omits any version numbers, uses semver ranges, or does not include all the modules involved in the bundle (including all dependencies), then it's expected that the content of the bundle URL will change over time, because new versions of modules may be released that satisfy your request criteria.

If you are risk-averse and want to ensure that the content of the bundle URL is always the same, you can obtain a 'shrinkwrapped' version by inspecting the comment at the top of any bundle response. Eg:

/v2/bundles/css?modules=o-grid,o-header

At time of writing this produces content prefixed with:


/** Shrinkwrap URL:
*    /v2/bundles/css?modules=o-grid%402.4.1%2Co-header%402.5.16&shrinkwrap=ftdomdelegate%402.0.3%2Co-assets%401.0.0%2Co-colors%402.4.7%2Co-dom%400.4.1%2Co-fonts%401.6.4%2Co-ft-icons%402.3.4%2Co-hierarchical-nav%401.1.3%2Co-hoverable%400.2.0%2Co-layers%401.0.0%2Co-squishy-list%401.1.0%2Co-useragent%402.2.0%2Co-viewport%401.0.0
*/
			

This locks down the precise versions of each constituent in the bundle to the version that currently best matches your request. You can then swap your original URL for the shrinkwrapped one to ensure that the returned content always remains unchanged:

File proxy (/files)

The build service also offers the ability to request, over HTTP or HTTPS, any single file from any known module component. This is useful to make use of modules that provide static resources such as images, fonts, audio, video or other media, without having to install them.

The file proxy is also used by the build service itself when creating bundles of JS or CSS that load external resources on demand. This allows CSS loaded through the build service /v2/bundles endpoint to still load any included backgrounds, and JavaScript modules may make AJAX requests to load static resources from their repos.

Caching and rebuilding

Requested bundles and files are generated on demand and then cached by the build service node that generated it (and also by the CDN). TTLs are set heuristically based on the mutability of the bundle content (ie if you use a fully shrinkwrapped URL, the TTL will be far longer). Build times can be significant (occasionally over a minute).

All bundle responses come with stale-while-revalidate and stale-on-error headers, which instructs CDNs to continue caching stale bundles while they are regenerated, reducing the chance of a public web user being blocked on a synchronous rebuild of a bundle which has expired in cache.

If you are loading build service URLs from the server side, you must fully respect cache control directives emitted by the build service.

Reliability

The build service is highly available, and shared-nothing, so each node is responsible individually for caching its own copy of the built bundles.

Concurrency

The build service is capable of running more than one build at the same time, but will not concurrently run more than one identical build. The second and subsequent requests for the same resource received while the first is building will not cause a second build to be started, but will simply receive a 202 response (if async) or block waiting for the original build to finish (if sync).

API reference

The current version of the API is 2. It has exactly the same API interface as v1, but uses Origami Build Tools for the builds. This uses libsass and is not 100% compatible with Ruby Sass, so we still make Ruby Sass builds available on the v1 endpoint. JavaScript bundles are built with OBT on both v1 and v2 endpoints.

GET /v2/bundles/js

Fetch a set of modules and build a JavaScript bundle.

Param Where? Description
modules Querystring A comma separated list of modules in the form modulename@version. Modulename may be a full URL (URL-encoded), or just the name of the repository. Where it is not a URL, the build service will try to find it as a repository from known Git sources. version is optional - if not present the build service will build the most recent version of the module, if it is present, it will be interpreted using Semver rules and the best matching version will be built. Using specific commit sha1s or branch names is not currently supported.
minify Querystring (Optional) If present and set to 'none', suppresses minification. Otherwise output will be minified automatically.
polyfills Querystring (Optional) If present and set to 'none', does not add polyfills to the output. Use this if your bundle is conflicting with other polyfills (e.g. through the Polyfill Service).
export Querystring (Optional) If present, generates a UMD bundle for the supplied export name. UMD works with other module systems and if no module system is found sets the specified name as a window global. If absent, the default export name Origami will be used. To export nothing, pass an empty string.
newerthan Querystring (Optional) If present and set to a valid ISO 8601 date in the past, the build service will not consider any cached copies of the build which are older than the date given, and if necessary will therefore begin a new build as if there were no build cached.
autoinit Querystring (Optional) If absent, or present and set to a truthy value, the bundle will include code to dispatch the o.DOMContentLoaded and o.load events when their browser-native counterparts occur. If set to 0, no auto-initialisation code will be included.

Due to the expected long duration of the build process, this method may return a redirect to keep the connection alive while the build continues in the background.

All complete bundle responses will include an X-FT-Build-Info response header, giving the bundle identifier, the date the build started in RFC1123 format, and the hostname of the build server:


X-FT-Build-Info: {build_hash}; {build_start_date}; {build_server};
X-FT-Build-Info: 1b1ab000a9b5642f6b8726039f1e79477b57c103; Tue, 15 Nov 2012 08:12:31 GMT; prod04-build02-uk1;
			

The following HTTP errors can be returned:

  • 400 Bad Request: The request was invalid
  • 409 Conflict: There was a dependency conflict in the bundle of modules specified
  • 500 Internal Server Error: There was a server error with the build service
  • 560 Compilation Error (non-standard): There was an error compiling the module code, reported from the build tools. This is likely an issue with the module, not with the build service itself

GET /v2/bundles/css

Fetch a set of modules and build a CSS bundle.

Param Where Description
modules Querystring A comma separated list of modules in the form modulename@version. Modulename may be a full URL (URL-encoded), or just the name of the repository. Where it is not a URL, the build service will try to find it as a repository from known Git sources. version is optional - if not present the build service will build the most recent version of the module, if it is present, it will be interpreted using Semver rules and the best matching version will be built. Using specific commit sha1s or branch names is not currently supported.
minify Querystring (Optional) If present and set to 'none', suppresses minification. Otherwise output will be minified automatically.
newerthan Querystring (Optional) If present and set to a valid ISO 8601 date in the past, the build service will not consider any cached copies of the build which are older than the date given, and if necessary will therefore begin a new build as if there were no build cached.

Due to the expected long duration of the build process, this method may return a redirect to keep the connection alive while the build continues in the background.

All complete bundle responses will include an X-FT-Build-Info response header, giving the bundle identifier, the date the build started in RFC1123 format, and the hostname of the build server:


X-FT-Build-Info: {build_hash}; {build_start_date}; {build_server};
X-FT-Build-Info: 1b1ab000a9b5642f6b8726039f1e79477b57c103; Tue, 15 Nov 2012 08:12:31 GMT; prod04-build02-uk1;
			

The following HTTP errors can be returned:

  • 400 Bad Request: The request was invalid
  • 409 Conflict: There was a dependency conflict in the bundle of modules specified
  • 500 Internal Server Error: There was a server error with the build service
  • 560 Compilation Error (non-standard): There was an error compiling the module code, reported from the build tools. This is likely an issue with the module, not with the build service itself

GET /v2/files/module@version/path

Loads and returns a file from a module component's repo.

Param Where Description
module URL Name of a git repo containing a the file to return.
version URL Semver compliant version number reference.
path URL Path to the file within the repo.

The most recent tagged version of the file that matches the specified Semver version number will be returned.

GET /v2/modules/module@version

Returns information in JSON format describing the module.

Property Type Description
bowerEndpoint String Name or URL of the package with an optional version number. It's in a format accepted by the bower install command.
bowerManifest Object Content of the .bower.json file that's created by the bower install command. It contains the exact version of the package and its dependencies.
origamiManifest Object Content of the origami.json file if it was found in the package.
build Object Results of build tasks performed on the package. All properties in this object are optional. Each property in this object contains an object with a valid and an optional error properties.
build.bundler.valid Boolean true if the package could be fetched and installed by the build service.
build.bundler.error String Message describing installation failure, if any.
build.origami.valid Boolean true if this is an Origami module and no conformance errors were found.
build.origami.error String Message describing the conformance error, if any.
build.css.valid Boolean true if CSS and Sass files in the package compiled successfully.
build.css.error String Sass compilation error message, if any.
build.js.valid Boolean true if JS was concatenated and minified without problems.
build.js.error String JS compilation error message, if any.

Deprecation

API versions

All Build Service endpoints are versioned, and the current version is v2. When deprecating old versions of the API we give at least three months notice, and will strive to notify all Build Service users.

Normally deprecated versions will be removed, and endpoints will start to respond with a 410 Gone status. We sometimes make an exception and redirect old versions to their newer counterparts when the API is compatible.

Version Status End Date Notes
v2 Current N/A
v1 Deprecated Requests to v1 endpoints will be redirected to v2 with a 301 status, rather than being removed. You're still encouraged to migrate to avoid the overhead of redirects.
- Deprecated Requests to unversioned endpoints will be redirected to v2 with a 301 status, rather than being removed. You're still encouraged to migrate to avoid the overhead of redirects.

Migrating from v1 to v2

The only potential breaking change in the v2 API is that we moved Sass compilation from Ruby Sass to LibSass. The only endpoint affected by this is /v2/bundles/css.

Try replacing v1 with v2 in your requests. If you're using very old versions of some modules, some of your styles may break. In this case you'll need to update to newer versions of these modules.

Before After
/v1/bundles/css?modules=… /v2/bundles/css?modules=…
/v1/files/… /v2/files/…

Migrating from unversioned to v2

Unversioned endpoints behave in exactly the same way as v1. See the v1 to v2 migration docs for information about breaking changes. To migrate, add v2 into the path before the endpoint:

Before After
/bundles/css?modules=… /v2/bundles/css?modules=…
/files/… /v2/files/…

Hostnames and CDNs

The Build Service is accessible using multiple different hostnames/paths. We only recommend using www.ft.com/__origami/service/build.

Hostname Status Notes
www.ft.com/__origami/service/build Current The hostname/path you should be accessing the Build Service through. Responses are cached with Fastly, and we use the stale-while-revalidate and stale-on-error cache extensions. This hostname/path is also multi-region with failover.
origami-build.ft.com Deprecated Responses are cached with Fastly. This will start redirecting to www.ft.com/__origami/service/build on .
build.origami.ft.com Deprecated Responses are cached with Akamai. This will start redirecting to www.ft.com/__origami/service/build on .
buildservice.ft.com Deprecated Responses are cached with Akamai. This will start redirecting to www.ft.com/__origami/service/build on .
origami-build-service-eu.herokuapp.com Development Responses are not cached. This hostname should never be used in production.
origami-build-service-us.herokuapp.com Development Responses are not cached. This hostname should never be used in production.
origami-build-service-qa.herokuapp.com Development This hostname points to a QA instance of the Build Service which has far fewer resources than production. Responses are not cached. This hostname should never be used in production.
origami-buildservice-eu.herokuapp.com Deprecated This URL no longer points to the Build Service.
origami-buildservice-qa.herokuapp.com Deprecated This URL no longer points to the Build Service.

Fastly Migration

The Build Service is migrating from Akamai to Fastly and also to a path on the ft.com domain. On we will start redirecting traffic from the following hostnames to www.ft.com/__origami/service/build:

  • origami-build.ft.com
  • build.origami.ft.com
  • buildservice.ft.com

We strongly recommend that you update all references to these deprecated hostnames to avoid redirects in your bundle and file requests. You will also get the benefit of the stale-while-revalidate and stale-on-error cache extensions, as well as multi-region support with failover. These all increase the resilience of the Build Service.

The redirects may have unexpected results if you access the Build Service through a proxy, and you may see multiple redirects if you're using both a deprecated hostname and API version.