npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

frappe-js-sdk

v1.7.0

Published

TypeScript/JavaScript client for Frappe Framework REST API

Downloads

5,894

Readme

frappe-js-sdk

TypeScript/JavaScript library for a Frappe Framework backend.

Features

The library currently supports the following features:

  • 🔐 Authentication - login with username and password (cookie based) + token based authentication
  • 🗄 Database - Get document, get list of documents, get count, create, update and delete documents
  • 📄 File upload
  • 🤙🏻 API calls

We plan to add the following features in the future:

  • Support for common functions like exists in the database.

The library uses Axios under the hood to make API calls to your Frappe backend.

Maintainers

| Maintainer | GitHub | Social | | -------------- | ----------------------------------------------- | ------------------------------------------------------------ | | Nikhil Kothari | nikkothari22 | @nik_kothari22 | | Janhvi Patil | janhvipatil | @janhvipatil_ | | Sumit Jain | sumitjain236 | LinkedIn |

Installation

npm install frappe-js-sdk

or

yarn add frappe-js-sdk

Initialising the library

To get started, initialise the library:

import { FrappeApp } from 'frappe-js-sdk';
//Add your Frappe backend's URL
const frappe = new FrappeApp('https://test.frappe.cloud');

In case you want to use the library with token based authentication (OAuth bearer tokens or API key/secret pairs), you can initialise the library like this:

import { FrappeApp } from "frappe-js-sdk";

const frappe = new FrappeApp("https://test.frappe.cloud", {
    useToken: true,
    // Pass a custom function that returns the token as a string - this could be fetched from LocalStorage or auth providers like Firebase, Auth0 etc.
    token: getTokenFromLocalStorage(),
    // This can be "Bearer" or "token"
    type: "Bearer"
})

Authentication

Initialise the auth library

const auth = frappe.auth()

Login a user:

This makes an API call to the /api/method/login endpoint.

auth
  .loginWithUsernamePassword({ username: 'admin', password: 'my-password' })
  .then((response) => console.log('Logged in'))
  .catch((error) => console.error(error));

Get currently logged in user:

This makes an API call to the /api/method/frappe.auth.get_logged_user endpoint.

auth
  .getLoggedInUser()
  .then((user) => console.log(`User ${user} is logged in.`))
  .catch((error) => console.error(error));

Logout:

This makes an API call to the /api/method/logout endpoint.

auth
  .logout()
  .then(() => console.log('Logged out.'))
  .catch((error) => console.error(error));

Forget Password

This makes an API sends a password reset link to the specified email address.

auth
  .forgetPassword('[email protected]')
  .then(() => console.log('Password Reset Email Sent!'))
  .catch(() => console.error("We couldn't find your account."));

Database

Initialise the database library

const db = frappe.db();

Fetch document using document name

db.getDoc('DocType', 'My DocType Name')
  .then((doc) => console.log(doc))
  .catch((error) => console.error(error));

Fetch list of documents

db.getDocList('DocType')
  .then((docs) => console.log(docs))
  .catch((error) => console.error(error));

Optionally, a second argument can be provided to filter, sort, limit and paginate results.

db.getDocList('DocType', {
  /** Fields to be fetched */
  fields: ['name', 'creation'],
  /** Filters to be applied - SQL AND operation */
  filters: [['creation', '>', '2021-10-09']],
  /** Filters to be applied - SQL OR operation */
  orFilters: [],
  /** Fetch from nth document in filtered and sorted list. Used for pagination  */
  limit_start: 5,
  /** Number of documents to be fetched. Default is 20  */
  limit: 10,
  /** Sort results by field and order  */
  orderBy: {
    field: 'creation',
    order: 'desc',
  },
  /** Group the results by particular field */
  groupBy: 'name',
  /** Fetch documents as a dictionary */
  asDict: false,
})
  .then((docs) => console.log(docs))
  .catch((error) => console.error(error));

Type declarations are available for the second argument in the source code.

Fetch number of documents with filters

const filters = [['creation', '>', '2021-10-09']];
const useCache = true; /** Default is false - Optional **/
const debug = false; /** Default is false - Optional **/

db.getCount('DocType', filters, cache, debug)
  .then((count) => console.log(count))
  .catch((error) => console.error(error));

Create a document

To create a new document, pass the name of the DocType and the fields to createDoc.

db.createDoc('My Custom DocType', {
  name: 'Test',
  test_field: 'This is a test field',
})
  .then((doc) => console.log(doc))
  .catch((error) => console.error(error));

Update a document

To update an existing document, pass the name of the DocType, name of the document and the fields to be updated to updateDoc.

db.updateDoc('My Custom DocType', 'Test', {
  test_field: 'This is an updated test field.',
})
  .then((doc) => console.log(doc))
  .catch((error) => console.error(error));

Delete a document

To create a new document, pass the name of the DocType and the name of the document to be deleted to deleteDoc.

db.deleteDoc('My Custom DocType', 'Test')
  .then((response) => console.log(response.message)) // Message will be "ok"
  .catch((error) => console.error(error));

Usage with Typescript

The library supports Typescript out of the box. For example, to enforce type on the updateDoc method:

interface TestDoc {
  test_field: string;
}
db.updateDoc<TestDoc>('My Custom DocType', 'Test', {
  test_field: 'This is an updated test field.',
});

The library also has an inbuilt type FrappeDoc which adds the following fields to your type declarations when you use it with the database methods:

export type FrappeDoc<T> = T & {
  /** User who created the document */
  owner: string;
  /** Date and time when the document was created - ISO format */
  creation: string;
  /** Date and time when the document was last modified - ISO format */
  modified: string;
  /** User who last modified the document */
  modified_by: string;
  idx: number;
  /** 0 - Saved, 1 - Submitted, 2 - Cancelled */
  docstatus: 0 | 1 | 2;
  parent?: any;
  parentfield?: any;
  parenttype?: any;
  /** The primary key of the DocType table */
  name: string;
};

All document responses are returned as an intersection of FrappeDoc and the specified type.

API Calls

Initialise the call library

const call = frappe.call();

Make sure all endpoints are whitelisted (@frappe.whitelist()) in your backend

GET request

Make a GET request to your endpoint with parameters.

const searchParams = {
  doctype: 'Currency',
  txt: 'IN',
};
call
  .get('frappe.desk.search_link', searchParams)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

POST request

Make a POST request to your endpoint with parameters.

const updatedFields = {
  doctype: 'User',
  name: 'Administrator',
  fieldname: 'interest',
  value: 'Frappe Framework, ERPNext',
};
call
  .post('frappe.client.set_value', updatedFields)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

PUT request

Make a PUT request to your endpoint with parameters.

const updatedFields = {
  doctype: 'User',
  name: 'Administrator',
  fieldname: 'interest',
  value: 'Frappe Framework, ERPNext',
};
call
  .put('frappe.client.set_value', updatedFields)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

DELETE request

Make a DELETE request to your endpoint with parameters.

const documentToBeDeleted = {
  doctype: 'Tag',
  name: 'Random Tag',
};
call
  .put('frappe.client.delete', documentToBeDeleted)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

File Uploads

Initialise the file library

const file = frappe.file();

Upload a file with on progress callback

const myFile; //Your File object

const fileArgs = {
  /** If the file access is private then set to TRUE (optional) */
  "isPrivate": true,
  /** Folder the file exists in (optional) */
  "folder": "Home",
  /** File URL (optional) */
  "file_url": "",
  /** Doctype associated with the file (optional) */
  "doctype": "User",
  /** Docname associated with the file (mandatory if doctype is present) */
  "docname": "Administrator",
  /** Field in the document **/
  "fieldname": "image"
}

file.uploadFile(
            myFile,
            fileArgs,
            /** Progress Indicator callback function **/
            (completedBytes, totalBytes) => console.log(Math.round((completedBytes / totalBytes) * 100), " completed")
        )
        .then(() => console.log("File Upload complete"))
        .catch(e => console.error(e))

License

See LICENSE.