# Writing plugins

As there is nothing better than learning by example, here is a simple plugin. It adds prefix to a key under which we will store our items. Plugin also adds this information to extra and provides method to get prefix used in that plugin.

## Plugin example

```javascript
export default function prefixPlugin(prefix) {
    return {
        hooks: [
            {
                // buildKey() method is used in almost all methods available
                // in stash-it, therefore this prefix will be 'glued' to the
                // key provided upon each of those mention method calls.
                event: 'preBuildKey',
                handler: ({ key, cacheInstance }) => {
                    const keyWithPrefix = `${prefix}.${key}`;

                    return { key: keyWithPrefix, cacheInstance };
                }
            },
            {
                // just before storing the item, the information about used
                // prefix is added to the `extra` of that item.
                event: 'preSetItem',
                handler: ({ key, value, extra, cacheInstance }) => {
                    const extraWithPrefix = Object.assign({}, extra, { prefix });

                    return { key, value, extra: extraWithPrefix, cacheInstance };
                }
            }
        ],
        createExtensions: () => {
            return {
                getPrefix() {
                    return prefix;
                }
            }
        }
    }
}
```

## Usage example

```javascript
import { createCache } from 'stash-it';
import createMemoryAdapter from 'stash-it-memory-adapter';
import createPrefixPlugin from 'some-module-we-created-this-plugin-in';

// First, cache instance
const adapter = createMemoryAdapter();
const cache = createCache(adapter);

// Now, plugin
const prefixPlugin = createPrefixPlugin('somePrefix');
const cacheWithPrefixes = cache.registerPlugins([ prefixPlugin ]);

// If we will store an item like so:
cacheWithPrefixes.setItem('itemKey', 'some value');

// And get it from cache (mind that I am using key used to set this item)
const item = cahceWithPrefixes.getItem('itemKey');

item.key; // 'somePrefix.itemKey

cacheWithPrefixes.getPrefix(); // somePrefix
```

## How does all that work

I will now explain what is going on in every part of this plugin.

### **prefixPlugin(prefix)**

As plugins are simple functions, here we name it `prefixPlugin` (there is no rule on how to name it), and pass `prefix` to it. In our usage example, we passed a string `'somePrefix'`.

This function will return an object that will have both an array of `hooks` and `createExtensions` method. As you remember, plugins must have at least one of them (either [hooks](/stash-it/plugins/hooks.md) or [createExtensions](/stash-it/plugins/createextensions.md)).

### **hooks**

Hooks are an array of objects that contain `event` names and `handlers`. Let's have a look at first hook:

```javascript
{
    event: 'preBuildKey',
    handler: ({ key, cacheInstance }) => {
        const keyWithPrefix = `${prefix}.${key}`;

        return { key: keyWithPrefix, cacheInstance };
    }
}
```

This hook uses `preBuildKey` event name. This means that whenever key will about to be built, whatever you will do in handler, will happen first, before building the key. Here, the key that user will pass, will be prefixed with our prefix. See: [preBuildKey](/stash-it/api/cacheinstance/buildkey-key.md#lifecycle). We're returning an object containing `key` and `cacheInstance`properties, as this is what [`buildKey`](/stash-it/api/cacheinstance/buildkey-key.md#lifecycle) lifecycle for `post` part will require.

2nd hook:

```javascript
{
    event: 'preSetItem',
    handler: ({ key, value, extra, cacheInstance }) => {
        const extraWithPrefix = Object.assign({}, extra, { prefix });

        return { key, value, extra: extraWithPrefix, cacheInstance };
    }
}
```

This hook uses `preSetItem` event name. This means that whenever an item will about to be set, whatever you will do in handler, will happen first, before setting that item. Here, we are taking prefix and adding it to the [extra](/stash-it/basic-structure.md#extra) data to store it in the [item](/stash-it/basic-structure.md).

Now that hooks are explained, let's have a look at createExtensions.

### **createExtensions()**

It must return an object with methods. Any methods? Not quite, have a look at [registerPlugins API](https://jaceks.gitbooks.io/stash-it/content/api/stash-it.html#registerpluginscacheinstance-plugins) to see when it can throw. So, this is our object, with methods we want our cache to be extended with:

```javascript
{
    getPrefix() {
        return prefix;
    }
}
```

### **What about lifecycle for each added methods, do I need to add them?**

No. Here, in above example you don't need to. But **it is a very good practice to add support for lifecycle of those methods**.

As above plugin did not needed that, let's have a look, again, at a plugin shown in [createExtensions docs](/stash-it/plugins/createextensions.md). I will (almost) copy and paste whatever is written there for the sake of having this info on one page here. First, the plugin:

```javascript
export default function multiPlugin(keys) {
    return {
        createExtensions: ({ cacheInstance, getPreData, getPostData }) => {
            return {
                getItems: (keys) => {
                    const preData = getPreData('getItems', { keys, cacheInstance });
                    const items = preData.keys.map(cacheInstance.getItem);
                    const postData = getPostData('getItems', { keys: preData.keys, items, cacheInstance: preData.cacheInstance });

                    return postData.items; 
                }
            }
        }
    }
}
```

This new (not present in stash-it) method is ready for events `preGetItems` and `postGetItems`. If you would be a creator of such a plugin, *your responsibility* is to provide detailed information how lifecycle of such a method looks like:

* what event names are here (by convention it's the same as created method's name, plus `pre` and `post` prefixes); here we will have `preGetItems` and `postGetItems`;
* what properties are passed in 2nd argument to `getPreData` and `getPostData`; here we will have:
  * for `pre` object: `{ keys, cacheInstance }`
  * and for `post`: `{ keys, items, cacheInstance }`
* what should be returned by each method (`getPreData` and `getPostData`); here we will have:
  * for `pre`: `{ keys, cacheInstance }` (so the same as object passed, convention, see below)
  * and for `post`: `{ keys, items, cacheInstance }` (same thing as for `pre`)
* what is returned by newly created method - here an array of items.

## Final word

There is no strict rule for what is needed to be passed from preData to postData. There is just a convention that I encourage you to follow, so that all plugins will work as you would expect them to:

* `pre` handlers should take an object as an argument, with properties being the arguments passed to extension, plus cacheInstance
* `pre` handlers should always return an object with those properties (and cacheInstance)
* extensions body (any functionality there is) should use / take data only returned by `pre` (including cacheInstance)
* `post` should take an object as an argument, the very same in structure as `pre` but with values taken from `pre` and with result of extensions method
* `post` should return an object with those properties
* finally that method should return extensions method value passed to `post` and returned by it
* you should always check for existence of `item` or `extra` as you might want to check their properties, but since they can be `undefined` - it's best to check that first.

{% hint style="info" %}
Remember that createExtensions will always be passed an object of such structure:\
{ cacheInstance, getPreData, getPostData }
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://stash-it.gitbook.io/stash-it/plugins/writing-plugins.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
