Our code review process vets the app code for code quality, correctness, and security. This section lists a broad set of guidelines to be followed when developing apps.
App best practices
In order to deliver a rich user experience to customers, we recommend that you adhere to the following best practices adopted for:
Notifications
Use Interface methods in apps to provide notification of an operation’s status. Also, notification messages should be clear and concise.
Dos
- Categorize notifications according to their types to make them meaningful (Success, Information, Warning, or Error).
- Keep the notification messages simple and easy to understand.
- Ensure that failure messages suggest an appropriate next step for users. For example: Retry at a later time, Contact the technical support team, or Refresh the page.
Don'ts
- Avoid passing API error responses or the corresponding text in notification messages as they can be technical in nature and ambiguous.
- Do not print javascript objects or stack traces in notifications.
- Do not use console logs as an alternative to notifications.
Input validation
Poor input validation can break an app or introduce security vulnerabilities. For fields in a standard installation page, you can set validations in the iparams.json file. Also, appropriate validation checks must be included for custom app settings pages and forms that accept user inputs. For an app that uses the app settings functionality, a validation logic must be included in the app code.
Dos
- Validate values based on the field types. For example, it should not be possible to enter alphabetic characters in numeric fields.
- For the apps developed on platform version 2.3 or earlier, ensure to validate auto-populated field values such as domain name, API key, or the complete web address associated with an account on the installation or app settings page.
- If the validation fails, the app should provide clear and concise messages and suggestions on how to address the errors.
- Provide helpful hints for complex form fields with appropriate example values.
- Mark required fields clearly.
- If your app uses the app settings functionality, add validation logic to the onSettingsUpdate method in the server.js file. This will ensure the settings entered on the app details page in Freshworks Marketplace are validated.
Don'ts
- Do not use regex patterns randomly. Although their brevity adds value, an incorrect pattern could do more harm than good.
- For the apps developed on platform version 2.3 or earlier, do not specify the protocol as part of the domain name if the input field type is domain on the installation or app settings page.
Lean apps and packaging
Remove unreachable code, unused variables, unwanted resources, and unused libraries to keep your app lean. Any source code that interacts with the Freshworks SDK must be packed within the app and submitted for review so that app users can tell what data from their account is used by the app. Business logic that uses this data can remain outside of the app package if required.
If a large part of the app source code is hosted outside the app, reviewers are likely to seek further information on the overall app architecture and how the business logic makes use of any personal information sourced by the app from a user’s account.
Dos
- Modularize code to enable better code organization, readability, and extensibility. Modules separate functions of the application into highly organized and manageable pieces.
- Use CDNs instead of locally packed libraries for code that does not use Freshworks platform APIs.
- Ensure that the app does not include iframes to load external JavaScript files, webpages, or web applications. Including iframes to load external files or applications can lead to security vulnerabilities by compromising the integrity of the code, versioning and compatibility issues, latency, privacy concerns, and so on.
- Ensure that globally accepted and publicly available frameworks and libraries, such as Vue.js, Lodash, jQuery and so on, are loaded via trusted CDNs and use HTTPS protocol.
- Remove unused npm modules from the code.
- Ensure to use trusted npm modules.
- Remove redundant or unused files from the app before packing.
- Ensure that the app uninstallation process undoes and cleans up the results of set-up actions, such as registering an external webhook.
- Use the fdk pack command to pack the application after testing.
Don'ts
- Do not access any code that makes use of the Freshworks platform APIs through CDN.
- Do not store sensitive information in cookies, sessionStorage, or localStorage.
Middleware management
If an app works with middleware, ensure that the app uses reliable and secure authentication to communicate with the middleware. While building an app, prioritize utilizing the features provided by the Freshworks platform over middleware, especially if they offer equivalent functions.
Dos
- Include the following details of the middleware in the README file for review.
- Details of the data that is passed to the middleware from the app.
- Usage of the data that is passed to the middleware.
- Duration for which the data is retained in the middleware.
- Reliability and availability guarantees available for the middleware.
- Process followed by middleware to remove stored data once the app is uninstalled.
- Ensure that any secrets used for middleware authentication is generated in the serverless app or another secure backend only.
- Ensure that the JWT secrets exposed to the frontend have a short lifespan, expiring within a day.
DO NOT include unauthenticated endpoints in the middleware.
Platform rate limits
An efficient app with the best performance must be built to function well within the platform rate limits.
- The rate limit to send HTTP requests using request method is 50 requests per minute per app per account. The rate limit may be breached if the app requires more than a few API requests to load.
- The rate limit for data storage is 50 requests per minute, with each request to store, retrieve, and delete data counting as one request. Alternate solutions must be implemented to handle the rate limit breach.
- For scheduled events, the number of One-Time events per app installation is limited and is not extendable.
- The time for execution of events is limited to 20 seconds and is not extendable. Alternate solutions must be implemented if the business logic for a serverless app is not designed to be time-bound.
- Ensure that when using the request method and data storage, the HTTP 429 responses are handled if the app makes multiple calls per invocation.
- Ensure that the HTTP 429 responses are handled for all the requests to Freshworks products and a retry mechanism is implemented. If a retry is not required, the error must be gracefully handled.
Important: Platform limits can be altered depending on the app usage and requirements. If required, you can raise a request to modify the rate limits.
UI styling
Freshworks products are known for their intuitive and visually appealing user experience. As an extension of the products, apps should blend into the product visually and not stand-out.
Dos
- Ensure that you adhere to the App UI guidelines.
- Perform cross-browser testing to ensure uniformity in the UI.
Coding best practices
For you to develop maintainable and reliable apps, we recommend that you adhere to the following best practices adopted for:
Logging
Although console logs help debug code, avoid indiscriminate use of console logs.
Dos
- Ensure that logs convey a meaningful message and proper context.
- Make use of different log levels (Info, Debug, warn, and Error) to categorize logs. For example, exceptions should be logged with console.error() as shown in the image.
![Correct console log](/docs/images/app-sdk/common-for-products/logging.png)
Don'ts
- Do not log secure data such as keys, tokens, credentials, and so on.
- Do not retain debugging logs and debugger breakpoint statements in the app source code.
- Do not use console.log() extensively as it leads to clutter.
![Incorrect console log](/docs/images/app-sdk/freshdesk/logging-2.png)
Asynchronous control flows
Javascript uses an asynchronous I/O model where I/O operations (AJAX calls, database operations, file-system access, and so on) run independent of the main program flow and use an event loop to run call back functions after completion of the I/O operations. Also, treating an asynchronous control flow like a synchronous flow could lead to unexpected failures or bugs in the app.
The Freshworks platform APIs are asynchronous in nature and it is essential to sequence them appropriately.
Dos
- Use promises to wrap asynchronous operations. Two or more asynchronous operations can be run back-to-back using promise chains. You can break the chain to obtain and process intermediate values.
- Check the browser compatibility when using external promise libraries, such as bluebird and Q, or native promise methods such as promise.all().
- Check the compatibility of modules with older environments when implementing complex control flows for asynchronous operations, such as the async module.
- In async function declarations, always await the asynchronus callbacks before return.
Don'ts
- Avoid callback hell.
- Do not use setTimeout() to cope with asynchronous flows.
- Do not access variables passed to or declared in the promise chain outside the promise.
- Avoid global variables unless it is absolutely required.
Error handling
Errors in code must be appropriately handled based on the control flow (synchronous or asynchronous). Ensure that you test failure cases extensively.
Dos
- Use the try..catch..finally block to handle synchronous errors.
- Handle errors in asynchronous operations or promises with the same level of detail as for synchronous operations. You can use the err parameter in callbacks and the catch block in promises for error handling.
- Ensure that the serverless component of the app returns a proper error response (for SMI apps and during App Setup Events) to the front end. This ensures business continuity in the face of unexpected errors and prevents negative experiences. DO NOT wrap everything inside a single try..catch block. Ensure that the code reacts appropriately to different exceptions.
Code minification and readability
Any code submitted as part of an app (with libraries included as assets) must not be in the minified or transpiled form. It has to be in a readable format to expedite code review and app certification processes.
Dos
- Ensure that submitted code is readable (with consistent naming schemes and indentation and follows the DRY principle).
- Although good code is self-documenting, use in-line documentation.
- If you use React, Ember, Vue, or any other front-end framework, include the source files of your app in the src directory. The contents of the src directory are packed along with the app when the fdk pack command is run and can be submitted for review.
ES5 compliance
Use ES5 standards for client-side code as ES6 standards disrupt backward compatibility.
Security
The following security-related guidelines are mandatory for all apps. We recommend that you adhere to the following best practices adopted for:
Installation parameters
If your installation parameters contain sensitive customer data, ensure that you secure them.
Dos
- Define iparams that store keys, credentials, or sensitive data as secure iparams.
- In the front end, ensure that you access secure iparams only by reference, using templating as part of Request method calls, as shown in the following snippet.
![Accessing secure iparams using request method](/docs/images/app-sdk/freshdesk/iprams.png)
Don'ts
- Do not hardcode keys, credentials, or sensitive data in the app.
- In the front end, do not use client.iparams.get() to fetch secure iparams. However, you can use client.iparams.get() to access non-secure iparams.
Request method
Apps depend on REST API calls, specifically when they are integrated with other products. Request method not only acts as a proxy to address CORS but also helps secure API calls. Using $.ajax calls instead of the platform Request method could lead to security vulnerabilities, especially when using secure iparams.
Dos
- Take into account the pagination settings and rate limits when the app makes calls to the REST APIs.
- Ensure that all API credentials are used only in the request headers. If there are exceptions, the tokens must expire within a maximum of 10 minutes.
- Use the Request method’s templating feature to securely inject iparams in authorization headers (front end).
![Iparams in authorization headers](/docs/images/app-sdk/freshdesk/request-api.png)
- If an app works with an external custom web service (such as one hosted with a cloud provider), the web service must be authenticated for any access so that privileged information is secure and only accessible through the app.
- Any external web services used must be capable of supporting considerable load and must have reliable uptime. Always prefer HTTPS over HTTP.
Don'ts
- Do not hardcode keys, tokens, or credentials in REST API calls.
- Avoid making HTTP requests as they are vulnerable to MITM attacks.
Code coverage
The code coverage summary lets you know the extent to which you have tested your app. For this, execute the fdk run command on the terminal. You can test your app for both positive and negative cases with equal importance.
Once you exit testing, the CLI prints the code coverage summary with which you can gauge how extensive your testing was. To access the latest code coverage report, navigate to the coverage folder from the app’s root directory.
![Correct code coverage](/docs/images/app-sdk/common-for-products/code-coverage.png)
Important:Each component in the coverage summary should be at least 80% for apps that are submitted to Freshworks Marketplace.
![Incorrect code coverage](/docs/images/app-sdk/common-for-products/code-coverage-incorrect.png)
To improve code coverage, you would need to test each and every functionality in your app for both success and failure cases, thereby detecting hidden bugs and improving the quality of the app.
The main components of the coverage summary are:
- Statement coverage: Checks if each statement in the code has been executed at least once.
- Branch coverage: Checks if each branch of each control structure has been executed. For example, in an IF statement, both the true and false branches need to be tested.
- Function coverage: Checks if each function (or subroutine) has been called in the code.
- Line coverage: Checks if each line of code has been executed (excluding comments/ conditionals). Note:Use the fdk pack command to pack the application after testing.
DO test positive and negative cases with equal importance.
DO NOT manually zip the app. Manual packing can corrupt or miss artifacts, pertaining to coverage metrics, in the .fdk directory and .report.json file.