UNPKG

frappe-js-sdk

Version:

TypeScript/JavaScript client for Frappe Framework REST API

450 lines (342 loc) 12.4 kB
# frappe-js-sdk TypeScript/JavaScript library for a [Frappe Framework](https://frappeframework.com) backend. <br /> <p align="center"> <a href="https://github.com/nikkothari22/frappe-js-sdk"><img src="https://img.shields.io/maintenance/yes/2024?style=flat-square" /></a> <a href="https://github.com/nikkothari22/frappe-js-sdk"><img src="https://img.shields.io/github/license/nikkothari22/frappe-js-sdk?style=flat-square" /></a> <a href="https://www.npmjs.com/package/frappe-js-sdk"><img src="https://img.shields.io/npm/v/frappe-js-sdk?style=flat-square" /></a> <a href="https://www.npmjs.com/package/frappe-js-sdk"><img src="https://img.shields.io/npm/dw/frappe-js-sdk?style=flat-square" /></a> </p> ## 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](https://axios-http.com) under the hood to make API calls to your Frappe backend. ## Maintainers | Maintainer | GitHub | Social | | -------------- | ----------------------------------------------- | ------------------------------------------------------------ | | Nikhil Kothari | [nikkothari22](https://github.com/nikkothari22) | [@nik_kothari22](https://twitter.com/nik_kothari22) | | Janhvi Patil | [janhvipatil](https://github.com/janhvipatil) | [@janhvipatil_](https://twitter.com/janhvipatil_) | | Sumit Jain | [sumitjain236](https://github.com/sumitjain236) | [LinkedIn](https://www.linkedin.com/in/sumit-jain-66bb5719a) | ## Installation ```bash npm install frappe-js-sdk ``` or ```bash yarn add frappe-js-sdk ``` ## Initialising the library 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" }) ``` ## Authentication #### 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. ```js 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. ```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.")); ``` ## Database #### 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 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`. ```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)); ``` ## Usage with Typescript 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<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: ```ts 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 ```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)); ``` ## File Uploads #### 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)) ``` ## License See [LICENSE](./LICENSE).