Can the Node.js Step Polling Function for Square API be Extended to Square Bookings or Appointments API?

This topic was automatically generated from Slack. You can find the original thread here.

I want a nodejs step to poll the Square Appointments API for new appointments/bookings using the latest square API. I see there is a polling function already for the “Catalog Item Updated from Square API” action. Can you extend this to the square Bookings or Appointments API (also using the cursor to paginate). Thanks.

Based on your request to poll the Square Appointments API for new appointments/bookings using Node.js, you can use the following Pipedream component code as a starting point. This code will make a paginated request to the Square Appointments API to retrieve new bookings, using a cursor to handle pagination: import { axios } from "@pipedream/platform"; export default defineComponent({ props: { square: { type: "app", app: "square", }, }, async run({ steps, $ }) { let appointments = []; let cursor = null; do { const response = await axios($, { url: `https://connect.squareup.com/v2/bookings`, headers: { Authorization: `Bearer ${this.square.$auth.oauth_access_token}`, }, params: { cursor: cursor, // Add any other parameters you need for filtering appointments }, }); appointments = appointments.concat(response.bookings); cursor = response.cursor; // The API response should include a cursor if there are more pages } while (cursor); return appointments; }, }); Please note that you’ll need to replace the URL with the correct endpoint for the Square Appointments API if it differs from the example above. Additionally, you may need to add any other parameters necessary for your use case, such as filters for the appointments you’re interested in. This code uses a do...while loop to continue making requests to the API as long as a cursor is provided, indicating that there are more pages of results. The appointments are collected into an array, which is returned at the end of the run method. Remember to test this code and adjust it as needed for your specific requirements and the Square API’s behavior.

Thank you. Why are you using axios over the native square sdk in pipedream?

The axios library is used within Pipedream components instead of the native Square SDK for a few reasons: 1. Consistency across Pipedream components: Pipedream uses axios for HTTP requests in all components for consistency. This allows users to learn one HTTP client and apply it across all integrations. 2. Simplified error handling: The @pipedream/platform package provides an axios wrapper that simplifies error handling, making it easier for users to understand and debug HTTP errors. 3. Direct access to HTTP response data: The Pipedream axios wrapper returns only the data property of the response object when the HTTP request succeeds, which is typically what users want to see. This streamlines the process of working with API responses. 4. No need for additional SDKs: Since Pipedream components are Node.js modules, they can make HTTP requests directly without the need for an SDK specific to each service. This reduces complexity and the number of dependencies. Here’s an example Pipedream component that uses axios to make a request to the Square API: import { axios } from "@pipedream/platform"; export default defineComponent({ props: { square: { type: "app", app: "square", }, }, async run({ steps, $ }) { return await axios($, { url: `https://connect.squareup.com/v2/customers`, headers: { Authorization: `Bearer ${this.square.$auth.oauth_access_token}`, }, }); }, }); This example demonstrates how to use axios to make an authenticated request to the Square API within a Pipedream component.

Okay - any chance I can reuse the polling function for square that Pipedream implemented for Square here components/square/sources/common/base-polling.mjs import square from “…/…/square.app.mjs”;
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from “@pipedream/platform”;

export default {
props: {
square,
db: “$.service.db”,
timer: {
type: “$.interface.timer”,
default: {
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
},
},
},
methods: {
_getLastTs() {
return this.db.get(“lastTs”) || 0;
},
_setLastTs(lastTs) {
this.db.set(“lastTs”, lastTs);
},
emitEvent(event) {
const meta = this.generateMeta(event);
this.$emit(event, meta);
},
generateMeta() {
throw new Error(“generateMeta is not implemented”);
},
},
};

Based on the code snippet you’ve provided, it looks like you’re interested in using a polling function from a Pipedream Square component. The code you’ve shared seems to be a part of a Pipedream component that uses the $.service.db to maintain state across executions and a timer to poll the Square API at regular intervals. To reuse this functionality, you would typically copy the relevant parts of the code into your own Pipedream component, making sure to replace any specific logic with your own (such as the generateMeta method, which you would need to implement). Here’s a simplified version of the polling component structure that you can use as a starting point: import { axios } from "@pipedream/platform"; export default defineComponent({ props: { square: { type: "app", app: "square", }, db: "$.service.db", timer: { type: "$.interface.timer", default: { intervalSeconds: 60, // Set your desired polling interval in seconds }, }, }, methods: { _getLastTs() { return this.db.get("lastTs") || 0; }, _setLastTs(lastTs) { this.db.set("lastTs", lastTs); }, emitEvent(event) { const meta = this.generateMeta(event); this.$emit(event, meta); }, generateMeta(event) { // Implement your logic to generate metadata for the event throw new Error("generateMeta is not implemented"); }, }, async run({ steps, $ }) { // Implement your logic to poll the Square API and emit events const lastTs = this._getLastTs(); // Example API request to Square (replace with your actual polling logic) const response = await axios($, { url: `https://connect.squareup.com/v2/your-endpoint`, headers: { Authorization: `Bearer ${this.square.$auth.oauth_access_token}`, }, }); // Process the response and emit events for (const event of response.data.items) { if (event.updated_at > lastTs) { this.emitEvent(event); this._setLastTs(event.updated_at); } } }, }); Please note that you’ll need to replace the generateMeta method with your own

Can I use db: “$.service.db”, in my own component?

It throws this error:
TypeError
Cannot read properties of null (reading ‘get’)

Based on the information provided, it seems like you’re encountering an error when trying to use the db service within your Pipedream component. The db service is indeed available for use in components to maintain state across executions. However, the error message you’re seeing suggests that the db service is not being initialized correctly, which is why you’re getting a TypeError when attempting to call the get method. Here’s a general example of how to correctly use the db service in a Pipedream component: export default defineComponent({ props: { db: "$.service.db", }, async run({ steps, $ }) { // Set a value in the db await this.db.set("key", "value"); // Get a value from the db const value = await this.db.get("key"); // Return the value return value; }, }) Make sure that you’re defining the db service in the props of your component and using this.db to access it within the run method. If you continue to experience issues, please ensure that your component structure matches the example above and that you’re using the latest version of the Pipedream platform. If you need further assistance, please visit Pipedream Support.

seems this.db is reserved for components. i’m using this not in a component but in a manual NodeJS step. How would I achieve the same within a nodejs step?

Based on the information provided, it seems you’re trying to use a data store within a Node.js code step in Pipedream. The correct way to reference a data store in a Node.js code step is by defining it as a prop in your component, which makes it available under this. Here’s an example of how you can define and use a data store in a Node.js code step: export default defineComponent({ props: { data: { type: "data_store" }, }, async run({ steps, $ }) { // Now you can access the data store at this.data const email = await this.data.get("email"); // Perform operations with the retrieved data }, }); Remember to use await when performing data store operations since they are asynchronous. If you have any further questions or need additional assistance, please let me know!