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