TypeScript/JavaScript client for Frappe Framework REST API
npm install frappe-js-sdkTypeScript/JavaScript library for a Frappe Framework backend.
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.
| Maintainer | GitHub | Social |
| -------------- | ----------------------------------------------- | ------------------------------------------------------------ |
| Nikhil Kothari | nikkothari22 | @nik_kothari22 |
| Janhvi Patil | janhvipatil | @janhvipatil_ |
| Sumit Jain | sumitjain236 | LinkedIn |
``bash`
npm install frappe-js-sdk
or
`bash`
yarn add frappe-js-sdk
To get started, initialise the library:
`js`
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:
`js
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"
})
`
#### Initialise the auth library
`js`
const auth = frappe.auth()
#### Login a user:
This makes an API call to the /api/method/login endpoint.
`js`
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.
`jsUser ${user} is logged in.
auth
.getLoggedInUser()
.then((user) => console.log())`
.catch((error) => console.error(error));
#### Logout:
This makes an API call to the /api/method/logout endpoint.
`js`
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.
`js`
auth
.forgetPassword('example@example.com')
.then(() => console.log('Password Reset Email Sent!'))
.catch(() => console.error("We couldn't find your account."));
#### Initialise the database library
`js`
const db = frappe.db();
#### Fetch document using document name
`js`
db.getDoc('DocType', 'My DocType Name')
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
#### Fetch list of documents
`js`
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.
`js`
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
`js
const filters = [['creation', '>', '2021-10-09']];
const debug = false; / Default is false - Optional /
db.getCount('DocType', filters, 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.
`js`
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.
`js`
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.
`js`
db.deleteDoc('My Custom DocType', 'Test')
.then((response) => console.log(response.message)) // Message will be "ok"
.catch((error) => console.error(error));
#### Rename a document
To rename a document, pass the name of the DocType, old name, new name, and an optional merge flag to renameDoc.
`js`
db.renameDoc('My Custom DocType', 'Old Name', 'New Name')
.then((response) => console.log(response.message)) // The message will reflect the updated document name.
.catch((error) => console.error(error));
#### Get field values of a document
To retrieve document values, pass the name of the DocType, field names (string or array), filters, and additional parameters to getValue.
`js
/ Get single field value /
db.getValue('My Custom DocType', 'Field_Name', [['Filter1', '=', 'Value1'],['Filter2', '=', 'Value2']])
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
/ Get multiple field values /
db.getValue('My Custom DocType', ['Field_Name1', 'Field_Name2'], [['Filter1', '=', 'Value1'],['Filter2', '=', 'Value2']])
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
`
#### Set field values of a document
To set field values, pass the name of the DocType, document name, field name (or an object of field-value pairs), and an optional value to setValue.
`js
/ Set value of a single field /
db.setValue('My Custom DocType', 'Test', 'Field_Name', 'Value')
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
/ Set values of multiple fields /
db.setValue('My Custom DocType', 'Test', {'Field_Name1':"Value1",'Field_Name2':"Value2"})
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
`
#### Get field value from a single doctype
To retrieve a field value from a Single-type doctype, pass the name of the DocType and field name to getSingleValue.
`js`
db.getSingleValue('My Custom Single DocType', 'Field_Name')
.then((response) => console.log(response.message)) // Message will reflect the value of the field.
.catch((error) => console.error(error));
#### Submit a document
To submit a document, pass the document object to submit.
`js`
db.submit(doc)
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
#### Cancel a document
To cancel a submitted document, pass the name of the DocType and document name to cancel.
`js`
db.cancel('My Custom DocType', 'Test')
.then((doc) => console.log(doc))
.catch((error) => console.error(error));
The library supports Typescript out of the box.
For example, to enforce type on the updateDoc method:
`ts`
interface TestDoc {
test_field: string;
}
db.updateDoc
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:
`ts`
export type FrappeDoc
/* 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.
#### Initialise the call library
`ts`
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.
`js`
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.
`js`
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.
`js`
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.
`js`
const documentToBeDeleted = {
doctype: 'Tag',
name: 'Random Tag',
};
call
.put('frappe.client.delete', documentToBeDeleted)
.then((result) => console.log(result))
.catch((error) => console.error(error));
#### Initialise the file library
`ts`
const file = frappe.file();
#### Upload a file with on progress callback
`js
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))
``
See LICENSE.