Skip to main content

Connectors

Connectors enable Stack9 to integrate with external services, APIs, databases, and cloud platforms. They provide a unified, configuration-driven way to connect to third-party systems without writing integration code.

Stack9 Console — Connectors list screen under Data Hub showing configured connectors with name, type, description and created/updated columns plus the add connector button

What are Connectors?​

Connectors are JSON configuration files that define how to connect to external services:

  • REST APIs - Connect to any HTTP/HTTPS API
  • Databases - Connect to PostgreSQL, MongoDB, MSSQL, Redis
  • Cloud Services - Connect to AWS S3, Azure Blob, DynamoDB, OpenSearch
  • Third-party APIs - Connect to SendGrid, GraphQL endpoints, OpenAPI services

When you define a connector, Stack9 automatically:

  • ✅ Manages authentication and credentials
  • ✅ Handles connection pooling
  • ✅ Secures sensitive data with environment variables
  • ✅ Provides type-safe access in queries and actions
  • ✅ Manages timeouts and retries

Why Use Connectors?​

Without Connectors (Manual Integration)​

// Scattered API clients, repeated configuration
import axios from 'axios';

const client = axios.create({
baseURL: process.env.EXTERNAL_API_URL,
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`,
'Accept': 'application/json'
}
});

// Repeated in multiple files
const response = await client.get('/customers');

With Connectors (Stack9 Approach)​

{
"name": "External Service",
"key": "external_service",
"type": "rest_api",
"configuration": {
"baseUrl": "%%APP_EXTERNAL_API_URL%%",
"headers": {
"Authorization": "Bearer %%APP_API_TOKEN%%",
"Accept": "application/json"
}
}
}

Benefits:

  • ✅ Centralized: All API configurations in one place
  • ✅ Secure: Credentials never hardcoded
  • ✅ Reusable: Use in queries, automations, and hooks
  • ✅ Environment-aware: Different configs per environment
  • ✅ Type-safe: TypeScript types generated automatically

Connector File Structure​

Connectors are defined in src/connectors/{connector_name}.json:

{
"key": "unique_connector_key",
"name": "Human Readable Name",
"description": "What this connector does",
"type": "connector_type",
"module": "module_name", // Optional
"configuration": {
// Type-specific configuration
}
}
Stack9 Console — Connector detail screen with the Configuration, Code view and Usages tabs open on Configuration, showing key, name, type and connection fields

Native Connectors​

Stack9 provides built-in connectors that require no configuration:

stack9_api​

Access Stack9's own entity APIs.

{
"name": "Stack9 API",
"key": "stack9_api",
"type": "stack9_api",
"description": "Native Stack9 API connector"
}

Usage in queries:

{
"key": "getcustomerlist",
"connector": "stack9_api",
"queryTemplate": {
"method": "post",
"path": "/customer/search",
"bodyParams": "{ \"$where\": { \"is_active\": true } }"
}
}

stack9_db​

Direct access to Stack9's database (PostgreSQL or MSSQL).

{
"key": "stack9_db",
"name": "Stack9 Database",
"type": "stack9_db",
"description": "Native Stack9 database connector",
"configuration": {
"client": "pg" // or "mssql" for SQL Server
}
}

Use in entity hooks with Knex:

await this.context.db.entity.knex('customers')
.where({ is_active: true })
.select('*');

Connector Types​

1. REST API Connectors​

Connect to any REST API service.

{
"name": "Address Lookup Service",
"key": "address_lookup_service",
"description": "Experian address lookup API",
"type": "rest_api",
"configuration": {
"baseUrl": "https://api.experianaperture.io",
"headers": {
"Auth-Token": "%%APP_EXPERIAN_ADDRESS_LOOKUP_TOKEN%%"
},
"authentication": {}
}
}

Configuration Options:

  • baseUrl (required): Base URL for all API calls
  • headers (optional): Default headers for all requests
  • authentication (optional): Authentication configuration

Authentication Types:

Basic Auth​

{
"authentication": {
"type": "basic",
"username": "%%APP_API_USERNAME%%",
"password": "%%APP_API_PASSWORD%%"
}
}

Bearer Token​

{
"authentication": {
"type": "bearer",
"bearer": "%%APP_API_TOKEN%%"
}
}

API Key​

{
"authentication": {
"type": "apiKey",
"apiKey": "%%APP_API_KEY%%"
}
}

Custom Authorization​

{
"headers": {
"Authorization": "Basic %%APP_WESTPAC_LOTTERY_SECRET_KEY%%"
}
}

2. Amazon OpenSearch​

Note: Amazon OpenSearch is defined in the ConnectorType enum but not validated in ConnectorSchemaValidator. Support may be limited.

Connect to AWS OpenSearch for full-text search and analytics.

{
"key": "opensearch",
"name": "OpenSearch",
"description": "AWS OpenSearch service",
"type": "amazon_opensearch",
"configuration": {
// Configuration schema not defined in validator
// Check with Stack9 support for proper configuration
}
}

3. Amazon S3​

Connect to AWS S3 for file storage.

{
"name": "Document Storage",
"key": "document_storage",
"type": "amazon_s3",
"configuration": {
"accessKeyId": "%%APP_AWS_S3_ACCESS_KEY_ID%%",
"secretAccessKeyId": "%%APP_AWS_S3_SECRET_ACCESS_KEY%%",
"bucketName": "%%APP_S3_BUCKET_NAME%%",
"s3ForcePathStyle": false
}
}

Configuration:

  • accessKeyId: AWS access key
  • secretAccessKeyId: AWS secret key
  • bucketName: S3 bucket name
  • arn (optional): Bucket ARN
  • s3ForcePathStyle (optional): Use path-style URLs
  • isCustomS3Endpoint (optional): For S3-compatible services
  • baseUrl (optional): Custom S3 endpoint URL

4. Azure Blob Storage​

Connect to Azure Blob Storage for file storage.

{
"name": "Azure Documents",
"key": "azure_documents",
"type": "azure_blob",
"configuration": {
"connectionString": "%%APP_AZURE_CONNECTION_STRING%%",
"containerName": "%%APP_AZURE_CONTAINER_NAME%%"
}
}

5. PostgreSQL Database​

Connect to external PostgreSQL databases.

{
"name": "External Database",
"key": "external_db",
"type": "postgresql",
"configuration": {
"host": "%%APP_DB_HOST%%",
"port": 5432,
"databaseName": "%%APP_DB_NAME%%",
"databaseUsername": "%%APP_DB_USERNAME%%",
"databasePassword": "%%APP_DB_PASSWORD%%",
"sslEnabled": true
}
}

Alternative with Connection String:

{
"configuration": {
"connectionString": "%%APP_DB_CONNECTION_STRING%%"
}
}

6. MongoDB​

Connect to MongoDB databases.

{
"name": "MongoDB Analytics",
"key": "mongodb_analytics",
"type": "mongodb",
"configuration": {
"host": "%%APP_MONGO_HOST%%",
"port": 27017,
"databaseName": "%%APP_MONGO_DB_NAME%%",
"databaseUsername": "%%APP_MONGO_USERNAME%%",
"databasePassword": "%%APP_MONGO_PASSWORD%%"
}
}

7. Redis​

Connect to Redis for caching and sessions.

{
"name": "Redis Cache",
"key": "redis_cache",
"type": "redis",
"configuration": {
"host": "%%APP_REDIS_HOST%%",
"port": 6379,
"password": "%%APP_REDIS_PASSWORD%%"
}
}

8. GraphQL​

Connect to GraphQL APIs.

{
"name": "GraphQL Service",
"key": "graphql_service",
"type": "graphql",
"configuration": {
"baseUrl": "%%APP_GRAPHQL_ENDPOINT%%",
"headers": {
"Authorization": "Bearer %%APP_GRAPHQL_TOKEN%%"
},
"authentication": {
"type": "bearer",
"token": "%%APP_GRAPHQL_TOKEN%%"
}
}
}

9. SendGrid​

Connect to SendGrid for email delivery.

{
"name": "Email Service",
"key": "email_service",
"type": "sendgrid",
"configuration": {
"accessToken": "%%APP_SENDGRID_API_KEY%%"
}
}

10. OpenAPI​

Connect to services with OpenAPI specifications.

{
"name": "OpenAPI Service",
"key": "openapi_service",
"type": "open_api",
"configuration": {
"specificationUrl": "https://api.example.com/openapi.json",
"basePath": "/v1",
"customHeaders": {
"X-API-Version": "2024-01-01"
},
"authentication": {
"type": "apiKey",
"apiKey": "%%APP_OPENAPI_KEY%%"
}
}
}

11. Amazon DynamoDB​

Note: Amazon DynamoDB is defined in the ConnectorType enum but not validated in ConnectorSchemaValidator. Support may be limited.

Connect to AWS DynamoDB.

{
"key": "dynamodb",
"name": "DynamoDB",
"type": "amazon_dynamodb",
"configuration": {
// Configuration schema not defined in validator
// Check with Stack9 support for proper configuration
}
}

12. Elasticsearch​

Connect to Elasticsearch clusters.

{
"name": "Elasticsearch",
"key": "elasticsearch",
"type": "elastic_search",
"configuration": {
"nodeOrCloudId": "%%APP_ELASTICSEARCH_NODE%%",
"auth": {
"type": "basic",
"username": "%%APP_ELASTICSEARCH_USERNAME%%",
"password": "%%APP_ELASTICSEARCH_PASSWORD%%"
}
}
}

Environment Variables​

Use %%VARIABLE_NAME%% syntax to inject environment variables securely.

Variable Naming Convention​

# .env file
APP_EXTERNAL_API_URL=https://api.example.com
APP_API_TOKEN=secret_token_here
APP_AWS_S3_BUCKET_NAME=my-documents

In Connector Configuration​

{
"configuration": {
"baseUrl": "%%APP_EXTERNAL_API_URL%%",
"headers": {
"Authorization": "Bearer %%APP_API_TOKEN%%"
}
}
}

Benefits:

  • 🔒 Secrets never committed to version control
  • 🌍 Different values per environment (dev, staging, prod)
  • 🔄 Easy rotation without code changes
  • ✅ Validated at startup

Using Connectors in Query Library​

Reference connectors in your queries:

{
"key": "lookup_address",
"name": "lookupAddress",
"connector": "address_lookup_service",
"queryTemplate": {
"method": "get",
"path": "/search",
"queryParams": {
"query": "{{searchTerm}}"
}
},
"userParams": {
"searchTerm": ""
}
}

When executed, Stack9:

  1. Resolves the connector configuration
  2. Injects environment variables
  3. Applies authentication
  4. Merges headers
  5. Executes the request

Using Connectors in Automations​

Use connectors in custom action types:

// action-types/fetch-external-data.ts
export class FetchExternalData extends CustomFunction {
async exec(): Promise<ActionTypeResponse> {
// Use connector through query library
const result = await this.context.services.query.execute(
'lookup_address',
{ searchTerm: '123 Main St' }
);

return { success: true, data: result };
}
}

Using Connectors in Entity Hooks​

Access connector data in hooks:

export class ValidateAddress extends CustomFunction {
async exec(): Promise<CustomFunctionResponse> {
const { entity } = this.context;

// Validate address using external service
const addressValidation = await this.context.services.query.execute(
'lookup_address',
{ searchTerm: entity.address }
);

if (!addressValidation.valid) {
return {
valid: false,
errors: [{
field: 'address',
message: 'Address not found'
}]
};
}

return { valid: true, entity };
}
}

Real-World Examples​

Example 1: Address Validation Service​

{
"name": "Address Lookup Service",
"key": "address_lookup_service",
"description": "Experian address lookup API",
"type": "rest_api",
"configuration": {
"baseUrl": "https://api.experianaperture.io",
"headers": {
"Auth-Token": "%%APP_EXPERIAN_ADDRESS_LOOKUP_TOKEN%%"
}
}
}

Query using this connector:

{
"key": "validate_address",
"connector": "address_lookup_service",
"queryTemplate": {
"method": "get",
"path": "/address/search/v1/autocomplete",
"queryParams": {
"country": "AUS",
"query": "{{address}}"
}
}
}

Example 2: Payment Gateway​

{
"name": "Payment Gateway",
"key": "payment_gateway",
"type": "rest_api",
"configuration": {
"baseUrl": "%%APP_PAYMENT_GATEWAY_URL%%",
"headers": {
"Authorization": "Basic %%APP_PAYMENT_GATEWAY_SECRET%%",
"Accept": "application/json",
"Content-Type": "application/json"
}
}
}

Example 3: Document Storage​

{
"name": "Document Storage",
"key": "document_storage",
"type": "amazon_s3",
"configuration": {
"accessKeyId": "%%APP_AWS_S3_ACCESS_KEY_ID%%",
"secretAccessKeyId": "%%APP_AWS_S3_SECRET_ACCESS_KEY%%",
"bucketName": "customer-documents-prod"
}
}

Use in action type:

export class UploadDocument extends CustomFunction {
async exec(): Promise<ActionTypeResponse> {
const { documentId, fileBuffer } = this.params;

// Stack9 handles S3 connection through connector
const s3Key = `documents/${documentId}.pdf`;
await this.context.services.storage.upload(
'document_storage',
s3Key,
fileBuffer
);

return { success: true, key: s3Key };
}
}

Best Practices​

1. Use Descriptive Names​

{
"key": "address_lookup_service", // ✅ Clear purpose
"key": "api1" // ❌ Unclear
}

2. Always Use Environment Variables​

{
"baseUrl": "%%APP_API_URL%%", // ✅ Secure
"baseUrl": "https://api.example.com" // ❌ Hardcoded
}

3. Add Descriptions​

{
"description": "Experian address lookup API for validating Australian addresses" // ✅ Helpful
}

4. Organize Headers Logically​

{
"headers": {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer %%APP_TOKEN%%",
"X-Custom-Header": "value"
}
}

5. Use Consistent Naming​

# Environment variables
APP_{SERVICE}_{RESOURCE}_{PROPERTY}

# Examples
APP_SENDGRID_API_KEY
APP_AWS_S3_BUCKET_NAME
APP_PAYMENT_GATEWAY_SECRET_KEY

6. Document Authentication Requirements​

{
"description": "Westpac Lottery Service - Requires Basic Auth with base64 encoded credentials"
}

7. Test Connector Configuration​

Before deploying, verify:

  • ✅ All environment variables are set
  • ✅ Authentication works
  • ✅ Base URL is correct
  • ✅ Headers are properly formatted

Common Patterns​

Multi-Environment Configuration​

# .env.development
APP_API_URL=https://api-dev.example.com
APP_API_TOKEN=dev_token

# .env.production
APP_API_URL=https://api.example.com
APP_API_TOKEN=prod_token

Same connector definition works across all environments:

{
"configuration": {
"baseUrl": "%%APP_API_URL%%",
"headers": {
"Authorization": "Bearer %%APP_API_TOKEN%%"
}
}
}

Retry Configuration​

For unreliable APIs, configure retries in query:

{
"connector": "external_api",
"retryOptions": {
"maxAttempts": 3,
"backoff": "exponential",
"retryOn": [408, 429, 500, 502, 503, 504]
}
}

Timeout Configuration​

Set timeouts to prevent hanging requests:

{
"connector": "slow_api",
"timeout": 30000 // 30 seconds
}

Troubleshooting​

Connector Not Found​

Error: Connector 'my_connector' not found

Solutions:

  1. Check the connector key matches exactly
  2. Ensure the file exists in src/connectors/
  3. Restart the Stack9 application

Authentication Failure​

Error: 401 Unauthorized

Solutions:

  1. Verify environment variable is set
  2. Check variable name spelling (%%APP_API_TOKEN%%)
  3. Confirm token is valid and not expired
  4. Test authentication separately with curl

Connection Timeout​

Error: ETIMEDOUT or ECONNREFUSED

Solutions:

  1. Verify baseUrl is correct
  2. Check network connectivity
  3. Confirm service is running
  4. Check firewall rules

Environment Variable Not Replaced​

Error: Seeing %%APP_VARIABLE%% in logs

Solutions:

  1. Ensure variable is defined in .env
  2. Restart application after adding variables
  3. Check variable name spelling matches exactly

Complete Schema Reference​

For the complete, detailed schema reference for all connector types and their configurations, see:

Next Steps​

Now that you understand Connectors, learn about: