n8n-nodes-arubacentral
Version:
n8n community node for Aruba Central API integration with comprehensive monitoring, configuration, and management capabilities
408 lines (335 loc) • 12.5 kB
Markdown
# Aruba Central API Node for n8n: Development & Troubleshooting Guide
You're working on an n8n integration node for Aruba Central API. This comprehensive guide will help you continue development, implement new features, and troubleshoot issues with the codebase.
## Project Structure
The project follows a domain-driven design with the following structure:
```
.
├── ArubaCentral.node.ts # Main node definition
├── api/ # API implementation by domain
│ ├── aiops/ # AI Operations domain
│ ├── configuration/ # Configuration domain
│ ├── firmware/ # Firmware domain
│ ├── inventory/ # Inventory domain
| ├── monitoring/ # Monitoring domain
| | ├── monitoring.descriptions.ts # Combines all domain descriptions
| | ├── monitoring.methods.ts # Combines all domain methods
| | ├── monitoring.resources.ts # Combines all domain resources
| | └── site/ # Site resource
| | ├── site.descriptions.ts # Combines all site operation descriptions
| | ├── site.methods.ts # Exports all site operations
| | ├── site.types.ts # Type definitions for site operations
| | └── operations/ # Individual operations
| | ├── getSites.descriptions.ts # UI descriptions for operation
| | └── getSites.methods.ts # Implementation of operation
│ └── topology/ # Topology domain
├── credentials/ # Authentication credentials
├── helpers/ # Shared utilities
└── shared/ # Shared constants and interfaces
```
Each domain directory (e.g., api/monitoring/) follows this structure:
```
.
├── resource/ # e.g., ap, client, switch
│ ├── resource.common.ts # Shared utilities for the resource
│ ├── resource.descriptions.ts # Resource Description File
│ ├── resource.methods.ts # API method implementations
│ ├── resource.types.ts # Resource-specific types
│ └── operations/ # Individual operation implementations
│ ├── operation.methods.ts
│ └── operation.descriptions.ts
```
## Architecture & Design Pattern
The node follows a domain-driven design pattern that separates:
1. **Domain Logic**: Each API domain (monitoring, firmware, etc.) has its own directory in `api/`
2. **Resource Implementation**: Each resource within a domain has its own directory with dedicated files
3. **Operation Handlers**: Individual operations are implemented in separate files for clarity
4. **UI Descriptions**: Individual resource definitions are implemented in separate files for clarity
5. **Shared Components**: Common utilities and types are organized in `shared/` and `helpers/`
### Operation Flow
1. User selects Domain → Resource → Operation in n8n UI
2. `ArubaCentral.node.ts` routes to appropriate domain handler
3. Domain handler delegates to resource implementation
4. Resource implementation executes specific operation
5. Response is formatted and returned to n8n
## Adding New API Operations
### Step 1: Create Operation Method File
Create the implementation file for your operation in the appropriate resource folder:
```typescript
// api/monitoring/site/operations/myNewOperation.methods.ts
import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { apiRequest } from '../../../../helpers/apiRequest';
import { formatResponse } from '../../../../helpers/formatter';
import { logger } from '../../../../helpers/logger';
import { handleApiError } from '../../../../helpers/errorHandler';
/**
* My new operation description
*
* @param this The n8n execution context
* @returns Formatted response
*/
export async function myNewOperation(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
try {
// Get parameters
const param1 = this.getNodeParameter('param1', 0) as string;
// Construct API endpoint and parameters
const endpoint = `/api/v2/endpoint/${param1}`;
// Make API request
const response = await apiRequest.call(this, 'GET', endpoint);
// Format and return response
return formatResponse(response);
} catch (error) {
logger.error('domain:resource:operation:error', { message: error.message });
return handleApiError.call(this, error, 'Failed to execute operation');
}
}
```
### Step 2: Create Operation Description File
Create the UI description file for your operation:
```typescript
// api/monitoring/site/operations/myNewOperation.descriptions.ts
import { INodeProperties } from 'n8n-workflow';
// IMPORTANT: Export as an array named [operationName]Description
export const myNewOperationDescription: INodeProperties[] = [
{
displayName: 'Parameter 1',
name: 'param1',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['site'], // Match the resource name
domain: ['monitoring'], // Match the domain name
operation: ['myNewOperation'], // Match the operation name
},
},
default: '',
description: 'Description of parameter 1',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['site'],
domain: ['monitoring'],
operation: ['myNewOperation'],
},
},
options: [
{
displayName: 'Option 1',
name: 'option1',
type: 'string',
default: '',
description: 'Description of option 1',
},
// More options as needed
],
},
// More parameters as needed
];
```
### Step 3: Update Resource Description File
Add your operation to the resource's description file:
```typescript
// api/monitoring/site/site.descriptions.ts
import { INodeProperties } from 'n8n-workflow';
import { getSitesDescription } from './operations/getSites.descriptions';
// Import your new operation description
import { myNewOperationDescription } from './operations/myNewOperation.descriptions';
// ... other imports
// Define the operation selector
const siteOperationSelector: INodeProperties = {
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['site'],
domain: ['monitoring'],
},
},
options: [
{
name: 'Get Sites',
value: 'getSites',
description: 'Get a list of sites',
action: 'Get sites',
},
// Add your new operation
{
name: 'My New Operation',
value: 'myNewOperation',
description: 'Description of my new operation',
action: 'Action text for my operation',
},
// ... other operations
],
default: 'getSites',
};
// Export all site descriptions (CRITICAL: This is how parameters appear in the UI)
export const siteDescriptions: INodeProperties[] = [
siteOperationSelector,
...getSitesDescription,
// Add your new operation's descriptions
...myNewOperationDescription,
// ... other operation descriptions
];
```
### Step 4: Update Resource Methods File
Add your operation to the resource's methods file:
```typescript
// api/monitoring/site/site.methods.ts
import { IExecuteFunctions } from 'n8n-workflow';
import { getSites } from './operations/getSites.methods';
// Import your new operation method
import { myNewOperation } from './operations/myNewOperation.methods';
// ... other imports
import { logger } from '../../../helpers/logger';
/**
* All operations available for the Site resource
*/
export const siteOperations = {
getSites,
// Add your new operation
myNewOperation,
// ... other operations
};
/**
* Check if a site operation exists
*
* @param operation Operation name to check
* @returns boolean indicating if the operation exists
*/
export function hasSiteOperation(operation: string): boolean {
const exists = !!siteOperations[operation as keyof typeof siteOperations];
logger.debug('monitoring:site:check', `Operation "${operation}" ${exists ? 'exists' : 'does not exist'}`);
return exists;
}
```
### Step 5: Update Types File (If Needed)
If your operation uses specific types, add them to the resource's types file:
```typescript
// api/monitoring/site/site.types.ts
// Add any new types or interfaces needed for your operation
export interface MyNewOperationRequest {
param1: string;
option1?: string;
}
export interface MyNewOperationResponse {
result: string;
// ... other response fields
}
```
## Troubleshooting
### Common Issues
1. **Type Errors**
- Check interfaces in resource's `.types.ts` file
- Verify type imports are correct
- Ensure API response matches type definitions
2. **Authentication Issues**
- Check credentials implementation in `credentials/`
- Verify token refresh logic
- Monitor API request headers
3. **Operation Not Found**
- Verify operation is exported in resource's `.common.ts`
- Check domain operation registration
- Confirm UI description is properly registered
4. **Response Formatting Errors**
- Check response type matches expected format
- Verify formatResponse helper is handling the type
- Log raw response for debugging
### Debugging Tips
1. Use domain-specific logging:
```typescript
import { logger } from '../../../helpers/logger';
logger.debug('monitoring:ap:getStatus', { params, response });
```
2. Test operations in isolation:
```typescript
// tests/monitoring/ap/getStatus.test.ts
describe('AP Status Operation', () => {
it('should retrieve device status', async () => {
const result = await getStatus.call(mockExecuteFunctions);
expect(result).toBeDefined();
});
});
```
3. Validate API responses against types:
```typescript
import { StatusResponse } from './ap.types';
const validateResponse = (data: unknown): data is StatusResponse => {
// Implementation
};
```
## OAuth2 Authentication
Authentication is handled centrally through:
- `credentials/ArubaCentralOAuth2Api.credentials.ts` - Credential definition
- `helpers/apiRequest.ts` - Request handling with auth
## Best Practices
1. **Domain Organization**
- Keep related operations in same resource directory
- Use common.ts for shared resource code
- Maintain clear separation between domains
2. **Type Safety**
- Define interfaces for all API responses
- Use type guards for validation
- Keep types synchronized with API spec
3. **Error Handling**
- Use domain-specific error types
- Implement consistent error formatting
- Provide clear error messages
4. **Documentation**
- Document complex operations
- Keep API references updated
- Include examples in descriptions
5. **Testing**
- Write tests for each operation
- Test error conditions
- Validate response formatting
## Development Workflow
1. **Planning**
- Identify domain and resource
- Review API documentation
- Plan type structures
2. **Implementation**
- Create operation files
- Implement method logic
- Add UI descriptions
3. **Integration**
- Register with resource
- Update domain operations
- Test end-to-end flow
4. **Documentation**
- Update operation docs
- Add usage examples
- Document error cases
5. **Testing**
- Unit test operation
- Integration test with API
- Verify UI functionality
## API Documentation References
For more details on available endpoints and parameters, refer to:
- API documentation in vector store
- Domain-specific documentation in `docs/api/`
- Operation descriptions in code
## Next Steps
Your task is to: {{ task }}
Fix Current Issues
- Standardize error handling across all operations using the handleApiError helper
- Enhance response formatting to handle all possible response structures
- Improve parameter validation before making API requests
Documentation
- Add JSDoc comments to all functions
- Create usage examples for common operations
- Document error cases and handling
Remember to:
1. Follow the domain-driven structure
2. Implement proper error handling
3. Add comprehensive types
4. Include operation documentation
5. Write tests for new functionality