Creating Your Own Internal API
This guide will walk you through creating and injecting custom Vue APIs for the Dashboard and @rancher/shell
package by simply dropping a .api.ts
file in a specific folder. Once set up, you can call your new APIs from any Vue component (e.g. this.$myNewApi.someMethod()
).
Overview
- Naming Convention: Your primary API classes should end in
.api.ts
(e.g.,my-api.api.ts
). - Location: Place these files in the
shell/plugins/internal-api/
directory (subdirectories are supported). - Static
apiName()
: Inside your class, define a static method namedapiName
(e.g.,static apiName() { return 'myNewApi'; }
), which determines the key by which your class is injected into Vue. - Instantiation: A Vue plugin (
internalApiPlugin
) automatically scansshell/plugins/internal-api/
, imports each.api.ts
file, creates a new instance of its default export, and injects it onto the Vue prototype as$myNewApi
.
Steps to Create & Use a New API
-
Create a File Within
shell/plugins/internal-api/
(or its subdirectories), create a.api.ts
file. For example:shell/plugins/internal-api/my-api.api.ts
-
Export a Default Class Your class should extend the provided
BaseApi
class. This ensures that your API has access to common functionality (like the Vuex store) without reimplementing it for every API. The class must have:- A constructor that calls the
BaseApi
constructor with the Vuex.Store instance. - A static
apiName
method defining how it will be injected. - Custom methods or logic you need to expose to components.
Example:
// shell/plugins/internal-api/my-api.api.ts
import { BaseApi } from "@shell/plugins/internal-api/shared/base-api";
export default class MyApi extends BaseApi {
// Name under which this API is injected => this.$myApi
// The `$` prefix will be automatically added when the API is injected
static apiName() {
return "myApi";
}
public doSomething() {
console.log("Hello from MyApi");
}
} - A constructor that calls the
-
Usage in Vue Components Once the file is saved, the
internalApiPlugin
(as shown in yourinstall-plugins.js
) will automatically discover your API file (e.g.my-api.api.ts
), instantiate it with the Vuex store, and inject an instance ofMyApi
onto the Vue prototype. This means that:- In an Options API component, you can access your API via this.$myApi.
- In a Composition API component, you can access it using getCurrentInstance() (or via other injection methods) to retrieve the global properties.
Options API Example
<template>
<div>Options API Component: Check the console for API output.</div>
</template>
<script>
export default {
name: "OptionsComponent",
mounted() {
// Using the injected API from the Vue prototype
this.$myApi.doSomething();
},
};
</script>
Composition API Example
<template>
<div>Composition API Component: Check the console for API output.</div>
</template>
<script setup>
import { getCurrentInstance, onMounted } from "vue";
// getCurrentInstance() gives you access to the component instance,
// which contains the proxy with all global properties including injected APIs.
const { proxy } = getCurrentInstance();
onMounted(() => {
// Access the API via the proxy
proxy.$myApi.doSomething();
});
</script>
TypeScript Augmentation (Optional)
To get TypeScript IntelliSense for this.$myApi
, you can manually augment the vue
module. You can create a declaration file (e.g., my-api.d.ts
) in the API Folder:
import type MyApi from "@shell/plugins/internal-api/my-api.api";
export {};
declare module "vue" {
interface ComponentCustomProperties {
$myApi: MyApi;
}
}
Now, TypeScript will recognize this.$myApi
in your Vue components.
File Structure Example
Below is an example file structure showing multiple APIs in subdirectories:
shell/plugins/internal-api/
├── my-api.api.ts
├── cluster/
│ ├── cluster-tools.api.ts
│ └── some-helper.ts <-- not injected
└── rancher/
└── rancher.api.ts
Each .api.ts
file is automatically discovered and instantiated. Helpers or partial modules that do not follow the .api.ts
naming scheme (like some-helper.ts
) won’t be injected.
How It Works
install-plugins.js
includesinternalApiPlugin
ininstallInjectedPlugins()
.internalApiPlugin
usesrequire.context
to scan subdirectories undershell/plugins/internal-api/
.- For each file matching
*.api.ts
, it:- Imports the file.
- Reads the default export (your class).
- Checks for a static
apiName
method; if not found, it falls back to the file name (An error will be thrown if extending theBaseApi
class). - Instantiates the class, passing in the Vuex store.
- Calls
inject(key, instance)
, which attaches your API toVue.prototype.$key
.
Conclusion
With this setup:
- Create a
.api.ts
class inshell/plugins/internal-api/
. - Define
static apiName() { return 'something'; }
. - Use it in Vue components via
this.$something
.
Everything else—from discovery to injection—happens automatically. This approach keeps your code organized, fosters easy extension, and saves you from having to manually edit the main injection logic each time you add a new API.