JavaScript SDK
This package is written in Typescript.
Installation
npm i jsonbank
# OR YARN
yarn add jsonbankInitialize
JsonBank class can be initialized with or without api keys.
Api Keys are only required when you want to access private/secured documents
const {JsonBank} = require("jsonbank")
const jsb = new JsonBank();const {JsonBank} = require("jsonbank")
// Initialize with Api keys.
const jsb = new JsonBank({
keys: {
pub: 'JSB_PUBLIC_KEY',
prv: 'JSB_PRIVATE_KEY',
}
});
// authenticate the api keys
await jsb.authenticate();Public Api Key
A read-only key. Use it to authenticate() and to read your own private documents. Public documents need no key at all.
Private Api Key
A write-only key, only needed to create, update or delete documents.
Check Authentication
To check if the user is authenticated, use the isAuthenticated method.
Make sure to have called authenticate method before.
await jsb.authenticate();
// check if the user is authenticated
jsb.isAuthenticated() // truePublic Content Methods
Public contents do not require authentication.
getDocumentMeta()
Get a public document meta details either by id or path. Does not return the content of the document. To get the content, use getContent method.
const meta = await jsb.getDocumentMeta("jsonbank/sdk-test/index");
// result is of type "JSB_Response.ContentMeta"
console.log(meta.id) // id of the document
console.log(meta.project) // project name
console.log(meta.name) // name of the document
console.log(meta.contentSize) // size object of the document
console.log(meta.path) // path of the document
console.log(meta.updatedAt) // date of last update
console.log(meta.createdAt) // date of creationtype ContentMeta = {
id: string;
project: string;
contentSize: {
number: number;
string: string;
};
path: string;
name: string;
folderId?: string;
updatedAt: string;
createdAt: string;
};getContent()
Get a public document content either by id or path. It returns the json parsed object. You can also pass a query to shape what you get back.
const content = await jsb.getContent("jsonbank/sdk-test/index");
// content is a json object{
"name": "JsonBank SDK Test File",
"author": "jsonbank"
}getContentAsString()
Get a public document content either by id or path as a string. It returns a string.
const content = await jsb.getContentAsString("jsonbank/sdk-test/index");
// content is a stringgetGithubContent()
Get a public json file from Github. This will read from the default branch of the repo.
It returns the json parsed object.
await jsb.getGithubContent("org/repo/file.json");
// example
await jsb.getGithubContent("jsonbankio/documentation/github-test.json"){
"name": "github-test.json",
"purpose": "This file is used to test the github json fetcher"
}getGithubContentAsString()
Same as getGithubContent but returns the content as a string.
await jsb.getGithubContentAsString("org/repo/file.json");
// example
await jsb.getGithubContentAsString("jsonbankio/documentation/github-test.json"){"name": "github-test.json", "purpose": "This file is used to test the github json fetcher"}Filtering Content (JSBQuery)
The read methods (getContent, getOwnContent, getGithubContent) take an optional query as their second argument. A query tells jsonbank to transform the json before sending it back, so you only get the data you need.
How filtering works
A query is an object with an apply modifier and optional args.
type JSBQuery = {
apply: string; // the modifier to run e.g "pick", "get"
args?: string | string[];
};Pass a single query, or an array of queries to run them one after another.
Example: pick
Pick only the fields you want.
const content = await jsb.getContent("jsonbank/sdk-test/index", {
apply: "pick",
args: ["name"]
});{
"name": "JsonBank SDK Test File"
}Example: get
Get a single value by its key.
const name = await jsb.getContent("jsonbank/sdk-test/index", {
apply: "get",
args: "name"
});"JsonBank SDK Test File"Available modifiers
Modifiers mirror their lodash counterparts:
chunk, first, last, nth, reverse, slice, take, takeRight, mapPick, mapOmit, get, at, has, hasIn, keys, values, valuesIn, keysIn, omit, unset, pick, castArray, isArray, find, findLast, filter, size, every, orderBy, sortBy, reject, shuffle, map, max, min, sum.
Access Own Content
Your own content is the documents in your projects. To read them, initialize with your api keys and authenticate first. See With Api Keys for more details.
authenticate() before using them. getOwnContent()
Get one of your documents either by id or path. Works for private documents too. It returns the json parsed object.
const content = await jsb.getOwnContent("sdk-test/index");
// content is a json objectgetOwnContentAsString()
Same as getOwnContent but returns the content as a string.
const content = await jsb.getOwnContentAsString("sdk-test/index");
// content is a stringgetOwnDocumentMeta()
Get the meta of one of your documents either by id or path. Returns the same ContentMeta type as getDocumentMeta.
const meta = await jsb.getOwnDocumentMeta("sdk-test/index");
// result is of type "JSB_Response.ContentMeta"hasOwnDocument()
Check if one of your documents exists, either by id or path.
await jsb.hasOwnDocument("sdk-test/index"); // true
await jsb.hasOwnDocument("does-not-exist"); // falsefalse instead of throwing when the document is not found. Managing Content
Create, update and delete documents in your projects.
createDocument()
Create a new document in a project. folder is optional, leave it out to create at the project root. content can be an object or a json string.
const doc = await jsb.createDocument({
name: "new_doc",
project: "sdk-test",
folder: "folder", // optional
content: {
name: "new_doc",
created: new Date().toISOString()
}
});type NewDocument = {
id: string;
name: string;
path: string;
project: string;
createdAt: string;
};createDocumentIfNotExists()
Same as createDocument, but if the document already exists it is fetched and returned instead of throwing.
const doc = await jsb.createDocumentIfNotExists({
name: "index.json",
project: "sdk-test",
content: { name: "JsonBank SDK Test File", author: "jsonbank" }
});
// when it already existed
doc.exists // trueupdateOwnDocument()
Update the content of one of your documents either by id or path. content can be an object or a json string.
const result = await jsb.updateOwnDocument("sdk-test/index", {
name: "JsonBank SDK Test File",
author: "jsonbank",
updatedAt: new Date().toISOString()
});
result.changed // true{
id: string;
changed: boolean;
message: string;
}deleteDocument()
Delete one of your documents either by id or path.
await jsb.deleteDocument("sdk-test/folder/new_doc");
// { deleted: true }{ deleted: false } instead of throwing when the document is not found. Folders
Group documents into folders inside a project.
getFolder()
Get a folder either by id or path.
const folder = await jsb.getFolder("sdk-test/folder");type Folder = {
id: string;
name: string;
path: string;
project: string;
parentFolder?: string;
createdAt: string;
updatedAt: string;
stats?: {
documents: number;
folders: number;
};
};getFolderWithStats()
Same as getFolder but also fills in stats (how many documents and folders are inside).
const folder = await jsb.getFolderWithStats("sdk-test/folder");
console.log(folder.stats) // { documents: 2, folders: 0 }createFolder()
Create a new folder in a project. folder is optional, use it to nest inside another folder.
const folder = await jsb.createFolder({
name: "folder",
project: "sdk-test"
});createFolderIfNotExists()
Same as createFolder, but if the folder already exists it is fetched and returned instead of throwing.
const folder = await jsb.createFolderIfNotExists({
name: "folder",
project: "sdk-test"
});
// when it already existed
folder.exists // trueListing
Browse what is inside a project, one level deep. Use these when you do not already know the ids or paths of your documents and folders.
authenticate() before using them. scanProject()
List the documents and folders of a project together. Leave the options out to list the project root, or pass folder to list inside a folder.
const listing = await jsb.scanProject("sdk-test");
console.log(listing.project.slug) // "sdk-test"
console.log(listing.documents.data.length) // documents on this page
console.log(listing.documents.meta.total) // documents in total
console.log(listing.folders.data.length) // folders on this pagetype ScanProject = {
project: {
slug: string;
title: string;
access: "public" | "private";
};
// only set when a folder was listed
folder?: {
id: string;
name: string;
path: string;
parentFolder?: string;
};
documents: {
data: ContentMeta[];
meta: PaginationMeta;
};
folders: {
data: Folder[];
meta: PaginationMeta;
};
};
type PaginationMeta = {
page: number;
perPage: number;
total: number;
lastPage: number;
};Each entry in documents.data is a ContentMeta and each entry in folders.data is a Folder.
To scan inside a folder, pass its id or its path. The folder you asked for comes back as listing.folder.
const listing = await jsb.scanProject("sdk-test", { folder: "folder" });
console.log(listing.folder.path) // "folder"folder is only set when you asked for one. It is undefined when the project root was listed. listDocuments()
Same as scanProject without the folders, so nothing you do not need is queried or paged. Content is not included, fetch it with getOwnContent.
const listing = await jsb.listDocuments("sdk-test", { perPage: 50 });
for (const doc of listing.documents.data) {
console.log(doc.path, doc.contentSize.string);
}type ListDocuments = {
project: { slug: string; title: string; access: "public" | "private" };
folder?: { id: string; name: string; path: string; parentFolder?: string };
documents: {
data: ContentMeta[];
meta: PaginationMeta;
};
};listFolders()
Same as scanProject without the documents.
const listing = await jsb.listFolders("sdk-test", {
sort: "createdAt",
order: "desc"
});
for (const folder of listing.folders.data) {
console.log(folder.path);
}type ListFolders = {
project: { slug: string; title: string; access: "public" | "private" };
folder?: { id: string; name: string; path: string; parentFolder?: string };
folders: {
data: Folder[];
meta: PaginationMeta;
};
};Listing options
Every option is optional. Leave one out and the server default is used.
listDocuments and listFolders return a single list, so they take a single page and perPage:
- folder: folder
idorpathto list inside. Leave it out to list the project root. - page: page to return. Defaults to
1. - perPage: results per page, up to
1000. Defaults to100. - sort: field to sort by, one of
name(default),createdAtorupdatedAt. - order:
asc(default) ordesc.
scanProject returns two lists that paginate independently, so it takes a page and a size for each:
- folder, sort, order: same as above,
sortandorderapply to both lists. - documentsPage, documentsPerPage: pagination of the documents list.
- foldersPage, foldersPerPage: pagination of the folders list.
Paginating
Each list is a single page. Read meta.lastPage to know how many there are and walk them:
let page = 1;
let lastPage = 1;
do {
const {documents} = await jsb.listDocuments("sdk-test", {page, perPage: 1000});
lastPage = documents.meta.lastPage;
for (const doc of documents.data) {
console.log(doc.path);
}
} while (page++ < lastPage);Uploading Files
Upload a json file straight from your file system. This is only available in Node.js through JsonBankNode.
uploadDocument: const { JsonBankNode } = require("jsonbank/node")uploadDocument()
Reads a file from disk and creates a document from it. name and folder are optional, name defaults to the file name.
const {JsonBankNode} = require("jsonbank/node")
const jsb = new JsonBankNode({
keys: {
pub: 'JSB_PUBLIC_KEY',
prv: 'JSB_PRIVATE_KEY',
}
});
await jsb.authenticate();
const doc = await jsb.uploadDocument({
file: __dirname + "/upload.json",
project: "sdk-test",
folder: "folder", // optional
name: "upload" // optional
});type NewDocument = {
id: string;
name: string;
path: string;
project: string;
createdAt: string;
};Error Handling
Methods throw a JSB_Error when something goes wrong. It is a normal Error with an extra code you can check.
try {
await jsb.createFolder({ name: "folder", project: "sdk-test" });
} catch (e) {
// e is a JSB_Error
if (e.code === "name.exists") {
// folder already exists, ignore it or fetch it instead
} else {
throw e;
}
}Common error codes:
notFound: the document or folder does not exist.name.exists: a document or folder with that name already exists.
hasOwnDocument() returns false, deleteDocument() returns { deleted: false }, and the ...IfNotExists() methods return the existing item with exists: true. Next steps
- Concepts: projects, paths, public vs private, and the key model.
- Webhooks: get notified when your documents change.
- Browse the other SDKs