[Files] Add developer documentation (#139698)

* wip on files docs

* wrote files tutorial v1

* minor tweaks and address PR feedback
This commit is contained in:
Jean-Louis Leysens 2022-09-01 10:43:50 +02:00 committed by GitHub
parent 73cce61a1e
commit e1e159104e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 148 additions and 0 deletions

View file

@ -128,6 +128,10 @@
"id": "kibDevTutorialDataSearchAndSessions",
"label": "data.search"
},
{
"id": "kibDevTutorialFilesService",
"label": "File service"
},
{
"id": "kibDevTutorialDataViews"
},

View file

@ -0,0 +1,144 @@
---
id: kibDevTutorialFilesService
slug: /kibana-dev-docs/files-service
title: Kibana File service
description: The files service abstracts over a blob store and provides CRUD functionality for blobs.
date: 2022-08-29
tags: ['kibana', 'onboarding', 'dev', 'architecture']
---
## Use cases
Blobs include any of the following:
* User-provided images, like avatars or logos in all image formats
* Documents, like PDFs or text files
* Binaries or scripts
* Visual or text outputs that need to be shared or downloaded at a later time
* Memoizing results of a compute intensive operation
* ...and many more!
<DocCallOut title="Note on performance">
The default blob store is Elasticsearch. The file service optimizes how Elasticsearch is used for blob storage, however Elasticsearch is not a blob store by design! **Please report any performance issues you notice ASAP!**
</DocCallOut>
<DocCallOut title="A few notes on security">
The file service does not encrypt contents at rest. No additional processing (like compression) is done to blob contents.
When storing data in Elasticsearch, the file service uses a system index. System indices have strict access controls so most users will not be able to access documents with blob contents directly. However, plugins are able to expose file contents over HTTP (more on this later) and there is nothing preventing a plugin from bypassing regular security checks which may unintentionally expose files.
To ensure the most secure file storage experience:
1. Only expose the needed actions against your files
2. Control access to your files using security tags on your HTTP routes
3. Do not ask users to store data in files that should not be visible to other users of the app
4. Do not store sensitive data in files - if you have a use case that requires this, please reach out to the Kibana App Services team
</DocCallOut>
### Files and Saved Objects
Files are a composition of Saved Objects (SOs) and blobs. SOs contain all metadata needed to provide file service functionality.
The file blob, or file content, is stored _separately_. When creating a file we first need to create the file metadata, which acts as an upload target, and then upload file content.
<DocCallOut title="File contents are immutable">
Once uploaded, the contents of a file do not change. Browsers, and other clients, should only need to download the contents of a file once, subsequent downloads should be served from the cache.
If you need to update the contents of a file, you should create a new file with new contents.
</DocCallOut>
#### Custom metadata
Consumers of the file service are able to decide what metadata they want to associate with a file. The file service provides the ability to search custom data which is useful for tagging and filtering your files &mdash; all metadata must be serializable to JSON. Learn more about how to specify custom metadata below.
### How to set up files for your plugin
All setup examples are based on the [`filesExample` plugin](https://github.com/elastic/kibana/blob/d431e87f7ff43833bff085e5bb5b2ab603bfa05d/x-pack/examples/files_example/README.md).
First add the `files` plugin as a required dependency in your `kibana.json`:
```json
"requiredPlugins": ["files"],
```
<br />
Next define your file kinds. Your plugin can have more than one file kind. Each file kind should represent a specific use case, for example: an image for user avatars.
```ts
import { FileKind } from '@kbn/files-plugin/common';
export const PLUGIN_ID = 'filesExample';
const httpTags = {
tags: [`access:${PLUGIN_ID}`], // ensure that only users with access to this plugin can files of this kind
};
export const exampleFileKind: FileKind = {
id: 'filesExample',
maxSizeBytes: 8 * 1024 * 1024, // 8 MiB
http: {
create: httpTags,
delete: httpTags,
download: httpTags,
getById: httpTags,
list: httpTags,
// share: httpTags,
// update: httpTags,
},
};
```
In this example we have chosen to disallow metadata updates and file sharing endpoints. **Make sure that you only expose the actions you need over HTTP**.
Now we are able to register this file kind with the file service:
```ts
// in your server-side plugin code
public setup(core: CoreSetup, { files }: { files: FilesSetup }) {
files.registerFileKind(exampleFileKind);
}
```
You are now able to access your files both from the server-side and the public-side of your plugin. For example, you can now list all of the files of a file kind by doing the following:
```ts
// in your public code
const result = await files.filesClientFactory.asScoped(exampleFileKind.id).list();
```
To create a new file from the browser you can do the following:
```ts
const { file } = await files.example.create({
name: 'my_file',
alt: 'My image',
/**
* How you define metadata is entirely up to you. Just make sure that your application
* remains compatible with previous versions of your metadata.
*/
meta: { myValue: 'test' } as MyMetadata,
mimeType: 'image/png',
});
// ...
await files.example.upload({ id: file.id, body: blob });
```
Now display your file to the world using the client side API:
```tsx
const { files: [file] } = await fileClient.find({ meta: { myValue: 'test' } });
<img
alt={file.alt ?? 'unknown'}
src={fileClient.getDownloadHref(file)}
/>
```
### Public components
<DocCallOut title="Under construction 🚧" color="warning">
The file service will expose a number of front-end components to ensure that a consistent UX is provided for.
Consumers of the file service will have access to lower-level APIs but it is highly recommended to use the existing UI components or to first reach out to the App Services team before building your own UI, others could also benefit from any UI improvements!
</DocCallOut>