A basic (work in progress) Vue.js and PrimeVue kitchen sink, showing various usage examples for some of the Preservica APIs.
See it in action on https://avbentem.github.io/preservica-api-demo
The Preservica APIs are typically used from an intermediate backend server, not directly from a browser. Preservica does not allow CORS to support using the APIs from a browser that is showing a website hosted on a random domain. So, to make this demo run in a standard browser on a non-Preservica domain, one of the following is needed:
-
A proxy on the same domain (same protocol, host and port) as this very demo. This is supported during development and with the Docker image; when using
yarn serve
ordocker run
then enter/proxy/
in the CORS proxy field of the configuration screen when running this demo. -
Or, a CORS-proxy on any domain and port, which adds or relaxes CORS headers to effectively allow everything we need:
-
It gets the full API URL appended, without any additional encoding. So, the appended URL should be fetched without first doing any decoding.
-
It should support OPTIONS, HEAD, GET and POST. (OPTIONS may be handled by the proxy.)
-
It should either use
Access-Control-Allow-Headers: *
or includepreservica-access-token
when getting an OPTIONS request withAccess-Control-Request-Headers: preservica-access-token
. -
To make this demo use the suggested (original) file name when downloading content, the proxy's response must include
Access-Control-Expose-Headers: Content-Disposition
.
-
A Preservica-provided <iframe>
is used to view documents. This works even when not being requested
through the proxy server, and uses a URL that includes a token
URL parameter. However, if keeping
the viewer open beyond the token's lifetime, then the <iframe>
may prompt for credentials. (A sane
browser should warn you that these credentials are not sent to this demo website, but to the
Preservica server that hosts the embedded viewer.)
The server sets the header Access-Control-Allow-Origin: https://<tenant>.access.preservica.com
,
and as the proxy server is not used here, the demo cannot interact with the embedded content. So, it
cannot tell if loading threw any HTTP error, and when content cannot be viewed using Preservica's
viewer, this would result in an embedded Preservica error page. To avoid that, the demo first makes
a proxied HEAD request to the same URL, for which the browser thinks it's not cross-domain. Next, if
this yields a 403 Forbidden or 404 Not Found for the given object then the viewer is simply not
embedded. Alternatively we could try to proxy the <iframe>
but that would break if the viewer
itself makes any absolute requests to other domains.
For thumbnails and to download content an HTTP header with an access token is needed, rather than a token in the URL. This implies that in this browser-based demo the thumbnails and content are first fully downloaded by the JavaScript code (using the configured proxy server), and only when completed the binary content is passed to the browser, or the browser is triggered to save the content. For large downloads, one may want a streaming solution, but in a real use case an intermediate backend server would proxy these downloads and add the required authorisation header on the fly.
Just like for the document viewer, for downloads first a HEAD request is made to only show the download option when we know that Preservica can deliver that.
The actual viewer depends on the document. Many file formats, including Word, Excel, PowerPoint and WordPerfect, are first converted to PDF using a server-side instance of LibreOffice. (See the document properties in the PDF viewer.) Some of the actual viewers:
- PDF: PDFjs
- Image: OpenSeadragon
- Rich text email message: server-side rendering to HTML
Some viewers may offer a full screen mode, which is explicitly allowed for our <iframe>
.
The viewer's URL is always <API host>/Render/render/external?entity=IO&entityRef=...&token=...
regardless the content type. It will enforce a download if it cannot find a suitable viewer. For
a single entity, the Content API's object-details
endpoint provides the actual URL in its links
array
for "rel": "render"
. This still needs &token=
appended to the URL. The Content API's search
endpoints do not provide this information, and this demo just uses a hardcoded base URL, which is
not future proof.
Assets that are not stored on a readable storage adapter are not available for preview or download.
This uses Vue 3, PrimeVue, PrimeIcons and PrimeFlex with TypeScript.
Details
This project was bootstrapped with Vue CLI v4.5.9. Initial vue create
options:
- Please pick a preset: Manually select features
- Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter, Unit
- Choose a version of Vue.js that you want to start the project with: 3.x (Preview)
- Use class-style component syntax? No
- Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
- Use history mode for router? (Requires proper server setup for index fallback in production) Yes
- Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
- Pick a linter / formatter config: Prettier
- Pick additional lint features: Lint on save, Lint and fix on commit
- Pick a unit testing solution: Jest
- Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
- Pick the package manager to use when installing dependencies: Yarn
Next, upgraded Prettier to fix errors in the generated code, configured .editorconfig
and Prettier
rules, added vue.config.js
to set the app's title, and added PrimeVue, PrimeIcons and PrimeFlex.
-
Download project dependencies:
yarn install
-
Compile and hot-reload for development:
yarn serve
This runs on http://localhost:9090 (or 9091 and up if ports are already in use) and also provides a proxy for the API, to avoid CORS limitations. To use that, enter
/proxy/
in the proxy field in the configuration screen when running the demo. (This does not work on the GitHub Pages hosted version.) -
Compile and minify for production:
yarn build
-
Lint, Prettify and fix files:
yarn lint
Unlike the pre-commit hook (see below), this is not limited to staged files.
The Dockerfile creates a temporary (partially cached) build image, builds the
project, and creates a final image that serves the static result using Nginx. To avoid CORS issues,
this also proxies requests for /proxy/https://eu.preservica.com/api/a/b/c
to https://eu.preservica.com/api/a/b/c
. To use that, enter /proxy/
in the proxy field in the
configuration screen when running the demo.
To build and tag:
docker build -t preservica-api-demo .
To run on http://localhost:9000:
docker run -p 9000:80 --rm preservica-api-demo
A pre-commit hook ensures that linting errors and formatting errors cannot be committed. Note that the hook uses lint-staged, which temporarily hides unstaged changes to partially staged files. This may make your IDE show warnings about files that were changed outside of the IDE.
Beware that Sourcetree may silently skip the pre-commit hook.
Preservica™ is a trademark of Preservica Ltd. The creator of this application is not affiliated with that organisation.