Skip to content

JavaScript SDK ​

This package is written in Typescript.

Installation ​

shell
npm i jsonbank
# OR YARN
yarn add jsonbank

Initialize ​

JsonBank class can be initialized with or without api keys.
Api Keys are only required when you want to access private/secured documents

typescript
const {JsonBank} = require("jsonbank")

const jsb = new JsonBank();
typescript
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.

typescript
await jsb.authenticate();

// check if the user is authenticated
jsb.isAuthenticated() // true

Public 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.

typescript
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 creation
typescript
type 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.

typescript
const content = await jsb.getContent("jsonbank/sdk-test/index");
// content is a json object
json
{
  "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.

typescript
const content = await jsb.getContentAsString("jsonbank/sdk-test/index");
// content is a string

getGithubContent() ​

Get a public json file from Github. This will read from the default branch of the repo.
It returns the json parsed object.

Note: Referenced file must be a public json file.
typescript
await jsb.getGithubContent("org/repo/file.json");

// example
await jsb.getGithubContent("jsonbankio/documentation/github-test.json")
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.

Note: Referenced file must be a public json file.
typescript
await jsb.getGithubContentAsString("org/repo/file.json");

// example
await jsb.getGithubContentAsString("jsonbankio/documentation/github-test.json")
text
{"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.

typescript
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.

typescript
const content = await jsb.getContent("jsonbank/sdk-test/index", {
  apply: "pick",
  args: ["name"]
});
json
{
  "name": "JsonBank SDK Test File"
}

Example: get ​

Get a single value by its key.

typescript
const name = await jsb.getContent("jsonbank/sdk-test/index", {
  apply: "get",
  args: "name"
});
text
"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.

Note: These methods need your public api key. Call 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.

typescript
const content = await jsb.getOwnContent("sdk-test/index");
// content is a json object

getOwnContentAsString() ​

Same as getOwnContent but returns the content as a string.

typescript
const content = await jsb.getOwnContentAsString("sdk-test/index");
// content is a string

getOwnDocumentMeta() ​

Get the meta of one of your documents either by id or path. Returns the same ContentMeta type as getDocumentMeta.

typescript
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.

typescript
await jsb.hasOwnDocument("sdk-test/index"); // true
await jsb.hasOwnDocument("does-not-exist"); // false
Note: Returns false instead of throwing when the document is not found.

Managing Content ​

Create, update and delete documents in your projects.

Note: These methods need your private api key.

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.

typescript
const doc = await jsb.createDocument({
  name: "new_doc",
  project: "sdk-test",
  folder: "folder", // optional
  content: {
    name: "new_doc",
    created: new Date().toISOString()
  }
});
typescript
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.

typescript
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 // true

updateOwnDocument() ​

Update the content of one of your documents either by id or path. content can be an object or a json string.

typescript
const result = await jsb.updateOwnDocument("sdk-test/index", {
  name: "JsonBank SDK Test File",
  author: "jsonbank",
  updatedAt: new Date().toISOString()
});

result.changed // true
typescript
{
  id: string;
  changed: boolean;
  message: string;
}

deleteDocument() ​

Delete one of your documents either by id or path.

typescript
await jsb.deleteDocument("sdk-test/folder/new_doc");
// { deleted: true }
Note: Returns { 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.

typescript
const folder = await jsb.getFolder("sdk-test/folder");
typescript
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).

typescript
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.

typescript
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.

typescript
const folder = await jsb.createFolderIfNotExists({
  name: "folder",
  project: "sdk-test"
});

// when it already existed
folder.exists // true

Listing ​

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.

Note: These methods need your public api key. Call 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.

typescript
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 page
typescript
type 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.

typescript
const listing = await jsb.scanProject("sdk-test", { folder: "folder" });

console.log(listing.folder.path) // "folder"
Note: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.

typescript
const listing = await jsb.listDocuments("sdk-test", { perPage: 50 });

for (const doc of listing.documents.data) {
  console.log(doc.path, doc.contentSize.string);
}
typescript
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.

typescript
const listing = await jsb.listFolders("sdk-test", {
  sort: "createdAt",
  order: "desc"
});

for (const folder of listing.folders.data) {
  console.log(folder.path);
}
typescript
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 id or path to 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 to 100.
  • sort: field to sort by, one of name (default), createdAt or updatedAt.
  • order: asc (default) or desc.

scanProject returns two lists that paginate independently, so it takes a page and a size for each:

  • folder, sort, order: same as above, sort and order apply 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:

typescript
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.

Note: Import the node version to get 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.

typescript
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
});
typescript
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.

typescript
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.
Note: Some methods don't throw, they return a value instead: hasOwnDocument() returns false, deleteDocument() returns { deleted: false }, and the ...IfNotExists() methods return the existing item with exists: true.

Next steps ​