Invoker
unlistedby Doston Kamilov
A Bruno-like API client. Create, run, and document HTTP requests with the .ivk file format.
โก Invoker
A Bruno-like API client for Obsidian.
Create, run, and document HTTP requests with the .ivk file format โ right inside your vault.
Why Invoker?
You already keep your notes in Obsidian. Your API documentation probably lives there too. Invoker turns those docs into a runnable API client โ no more jumping between Postman, Bruno, and your docs. Write a request in a .ivk file, hit Send, get a response. Embed the same request inline inside a markdown doc and let your team run it with one click.
Features
- ๐ฎ Full-featured request editor โ method, URL, headers, body, auth, scripts
- ๐
.ivkfile format โ plain text, git-friendly, AI-friendly - ๐ Environments & variables โ
{{baseUrl}},{{sessionSecret}}resolved at send time - ๐ Pre/post/test scripts โ sandboxed JavaScript with
ivkandresglobals - ๐ Chain requests โ save values from one response, use them in the next
- ๐จ Syntax highlighting โ JSON, JavaScript, and
{{variable}}highlighting - โ๏ธ Inline markdown embedding โ
ivkcode blocks with Run button in your docs - ๐ Auth shorthands โ
@auth bearer {{token}},@auth basic user pass - ๐งช Built-in testing โ
test()/expect()assertions on responses - ๐ก Uses Obsidian's HTTP client โ bypasses CORS, works in desktop and mobile
Install
From Obsidian Community Plugins (coming soon)
- Open Obsidian โ Settings โ Community plugins
- Click Browse and search for "Invoker"
- Click Install, then Enable
Manual install
- Download
main.js,manifest.json, andstyles.cssfrom the latest release - Create a folder
.obsidian/plugins/invoker/in your vault - Drop the three files in that folder
- Reload Obsidian, then enable the plugin in Settings
From source
git clone https://github.com/doossee/obsidian-invoker.git
cd obsidian-invoker
npm install
npm run build
# Copy main.js, manifest.json, styles.css to .obsidian/plugins/invoker/
Quick start
1. Create a request
Create a new file hello.ivk:
@name Hello World
GET https://httpbin.org/get
Accept: application/json
Open it โ the visual editor renders. Click Send.
2. Use variables
Set up an environment in Settings โ Invoker:
| Variable | Value |
|---|---|
baseUrl | https://httpbin.org |
Your request now works across environments:
@name Hello World
GET {{baseUrl}}/get
3. Chain requests with scripts
@name Login
POST {{baseUrl}}/api/login
Content-Type: application/json
{
"email": "{{email}}",
"password": "{{password}}"
}
> post {
ivk.env.set("token", res.body.access_token);
}
Now any other .ivk file can use @auth bearer {{token}} and it just works.
4. Embed in markdown docs
In any .md file, add:
## Login
Before calling protected endpoints, get a session token:
```ivk
path: api/login.ivk
show: full
```
You get a runnable widget inline in your docs. One source of truth for docs + testing.
The .ivk format
@name Login
@description Send OTP to phone number
@auth bearer {{sessionSecret}}
@timeout 30s
@tag auth
POST {{baseUrl}}/api/login
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "Auth.login",
"params": { "phone": "{{phone}}" }
}
> pre {
ivk.env.set("reqTime", Date.now());
}
> post {
ivk.env.set("user_id", res.body.result.user_id);
}
> test {
test("returns user_id", () => {
expect(res.status).toBe(200);
expect(res.body.result.user_id).toBeDefined();
});
}
Sections (in order):
@directivesโ metadata (name, auth, timeout, description, tag, body)METHOD URLโ required, e.g.POST https://api.example.comKey: Valueheaders โ until empty line- Raw body โ any format (JSON, XML, form-data, plain text)
> pre { }โ pre-request script (optional)> post { }โ post-response script (optional)> test { }โ test assertions (optional)
Minimal file is one line: GET https://api.example.com/health
See FORMAT.md for the full specification.
Scripting API
Pre-request script has access to ivk.request, ivk.env. Post-response has res (status, body, headers, time) and ivk.env.
// Read/write environment variables
ivk.env.get('name');
ivk.env.set('name', 'value');
// Modify the outgoing request (pre only)
ivk.request.headers['X-Custom'] = 'value';
ivk.request.url = '...';
ivk.request.body = '...';
// Read the response (post/test)
res.status; // number
res.body; // parsed object
res.headers; // object
res.time; // ms
// Logging (pre/post/test)
ivk.log('message');
// Tests (test block only)
test('description', () => {
expect(value).toBe(expected);
expect(value).toBeDefined();
expect(value).toContain(sub);
expect(value).toBeGreaterThan(n);
});
Documentation
docs/FORMAT.mdโ complete.ivkformat specdocs/SCRIPTING.mdโ scripting API referencedocs/ARCHITECTURE.mdโ how the plugin is structuredCHANGELOG.mdโ release history
Contributing
Contributions welcome! See CONTRIBUTING.md for development setup, code style, and PR guidelines.
Support
- ๐ Report a bug
- ๐ก Request a feature
- ๐ฌ Discussions
- โค๏ธ Sponsor
License
MIT โ see LICENSE.
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.