I am building a custom n8n node and stumbled in some questions about what would be the best practices for developing them. I read the checklist before submitting a new node, but I was wondering if some experienced developers could share other best patterns and insights about the decisions that they encountered when designing the nodes.
For example, when designing a node for interacting with an API, should we make its operations as close as possible to the API requests (e.g. one API call per node operation)? I think that could be a good practice since it will avoid unexpected behavior for someone who is used to the API. On the other hand, some beginner users could find the API calls too complex and it would be better to do many API calls in a single node operation…
For example, when designing a node for interacting with an API, should we make its operations as close as possible to the API requests (e.g. one API call per node operation)? I think that could be a good practice since it will avoid unexpected behavior for someone who is used to the API. On the other hand, some beginner users could find the API calls too complex, and it would be better to do many API calls in a single node operation…
If understood well, it depends on the operation. Normally we try to make it as easy as possible for the customer. For example, imagine that you need your node to create a charge. To do so, the API needs to call two different endpoints:
Endpoint 1: Create a card, which returns a Card ID.
Endpoint 2: Create the change, referencing the Card ID.
In this case, we would probably have the functionality charge:create, asking all the parameters to create a card and all the parameters to create a charge. Later, when the node is executed, we first call the first endpoint, grab the Card ID, and then create the charge.
We definitely want to have more articulate guidance in future to empower our community to build. We recently released the first resources for custom node development so expect there to be more granular resources coming once we’ve gotten coverage of the core pieces.
Until then, hopefully these examples help in making the right contextual decision for the nodes you’re looking to create:
the Typeform API by default returns a not-so-easy to work with response for Form responses. So we have a “simplify” option that is true by default. When active, this option returns a very simply object with simply key:values for each question answered. So under the hood we’re performing that mapping. This was a case-by-case decision since most usecases just need this data.
Another example: Airtable and Jira have some really powerful internal syntax to create powerful queries or operations. For JIRA, this is JQL. For Airtable, in api terms this is their “filter by formula” which can use any Airtable formulae (of which there are over 50, from time utilities to math functions, logic etc). In these cases, we don’t reinvent the wheel but have a text input so users can simply read up on the tool’s native docs and implement something very specific that would be very cumbersome to model completely with UI.
Feel free to message me on here if you have any specific questions that come up during development. This will also help me understand what sorts of questions arise during real world development in the community
Hi Max, I was wondering what is the best practice regarding fetching pages from a paginated API
I want to implement an operation in my node for getting all entries of an API endpoint, and there will be a lot of entries and many pages to fetch. Is there a preferred pattern between these two approaches (or even a better approach)?
(1) Make the node get just one page and expect that the user will use this workflow pattern to get all entries;
(2) Make the node directly retrieve all the pages, and output the concatenation of all pages’ entries
Hi @htadashi - that is a great question! For endpoints that have pagination, we offer this to the user as an option - a “Return all” bool toggle. The Hubspot Regular node can be used as a reference in terms of how this is setup in code + UI:
As for whether or not Return All is true or false by default, there are some nodes that deviate from this pattern but typically should be false by default.