|
| 1 | +# Connector development guidelines |
| 2 | + |
| 3 | +This guide outlines the complete lifecycle for developing Ballerina connectors for BI, from initial conception through general availability. Following these guidelines ensures consistent quality and maintainability across all connector implementations. |
| 4 | + |
| 5 | +## Naming conventions |
| 6 | + |
| 7 | +### Package names |
| 8 | + |
| 9 | +Package names should use lowercase letters and be descriptive of the service or API being integrated. The name should clearly indicate the external system the connector interacts with. |
| 10 | + |
| 11 | +**Examples:** |
| 12 | +- `ballerinax/salesforce` |
| 13 | +- `ballerinax/stripe` |
| 14 | +- `ballerinax/mongodb` |
| 15 | + |
| 16 | +### Submodules |
| 17 | + |
| 18 | +Submodules should be named in lowercase letters and should reflect the sub-functionality they contain. Submodules should primarily organize code structure within a single connector package. Avoid defining multiple sub-clients in each submodule. |
| 19 | + |
| 20 | +### Hierarchical packages |
| 21 | + |
| 22 | +Hierarchical package names are recommended when you need to distinguish between multiple connectors for the same vendor or service provider. This approach is particularly useful for SaaS products with independent API versioning. |
| 23 | + |
| 24 | +**When to use hierarchical packages:** |
| 25 | +- When dealing with the same vendor but different services (e.g., `ballerinax/azure.cosmosdb` vs `ballerinax/azure.storage`) |
| 26 | +- When a SaaS product has multiple independent APIs with separate versioning (e.g., `ballerinax/salesforce.bulk` vs `ballerinax/salesforce.soap`) |
| 27 | + |
| 28 | +**Examples:** |
| 29 | +- `ballerinax/azure.cosmosdb` |
| 30 | +- `ballerinax/azure.storage` |
| 31 | +- `ballerinax/salesforce.bulk` |
| 32 | +- `ballerinax/salesforce.commons` |
| 33 | +- `ballerinax/openai.chat` |
| 34 | +- `ballerinax/googleapis.gmail` |
| 35 | + |
| 36 | +### Best practices |
| 37 | + |
| 38 | +- **Clarity and readability**: Use simple nouns that clearly represent the service. Package names should be clear and descriptive, making it easy for developers to understand the purpose of each package. Names like `azureEventHub` or `azure_event_hub` are not idiomatic in Ballerina. |
| 39 | +- **Avoid complex patterns**: Do not use camelCase or snake_case in package names |
| 40 | +- **Use recognized abbreviations**: Only use abbreviations that are widely recognized by developers (e.g., `aws`, `gcp`) |
| 41 | +- **Maintain consistency**: Ensure naming is consistent throughout the connector for an intuitive developer experience |
| 42 | +- **Avoid overly deep hierarchies**: While nesting is useful for organization, avoid creating overly deep hierarchies as they increase complexity |
| 43 | +- **Avoid split-module conditions**: A split-module condition occurs when different package versions contain the same module, which causes build failures. Choose hierarchical structures carefully to minimize such situations. |
| 44 | + |
| 45 | +## Repository setup |
| 46 | + |
| 47 | +Connectors are developed in dedicated GitHub repositories following a consistent naming pattern: |
| 48 | + |
| 49 | +**Repository Pattern:** `module-[org-name]-[connector-name]` |
| 50 | + |
| 51 | +**Examples:** |
| 52 | +- `module-ballerinax-azure.cosmosdb` |
| 53 | +- `module-ballerinax-salesforce` |
| 54 | +- `module-ballerinax-stripe` |
| 55 | + |
| 56 | +This structure allows for independent versioning, testing, and release cycles for each connector. |
| 57 | + |
| 58 | +## Project structure |
| 59 | + |
| 60 | +A standard connector library includes the following components: |
| 61 | + |
| 62 | +### Required components |
| 63 | + |
| 64 | +- **Ballerina source code**: Core implementation of the connector |
| 65 | +- **Tests**: Unit and integration(if possible) tests to ensure functionality |
| 66 | +- **Examples**: Sample code demonstrating connector usage |
| 67 | +- **Documentation**: User-facing documentation and API references |
| 68 | + |
| 69 | +### Optional components |
| 70 | + |
| 71 | +- **Native code**: Platform-specific implementations when required |
| 72 | +- **Compiler plugins**: Custom compile-time behaviors |
| 73 | +- **Compiler plugin tests**: Tests for custom compiler plugins |
| 74 | +- **Integration tests**: End-to-end tests (typically in separate packages) |
| 75 | + |
| 76 | +### Build and release tools |
| 77 | + |
| 78 | +- **Build tool**: Gradle |
| 79 | +- **CI/CD**: GitHub Actions for automated testing and releases |
| 80 | + |
| 81 | +**Build automation for different connector types:** |
| 82 | + |
| 83 | +- **Modules bundled with ballerina-distribution**: Use intermediate packs that incorporate timestamped versions from the Standard Library. This approach maintains build stability and enables prompt failure detection via GitHub packages. |
| 84 | + |
| 85 | +- **Ballerinax modules published independently**: Should use nightly builds from `ballerina-distribution` instead of timestamped builds. The nightly pack can be obtained from the Daily Build in the ballerina-distribution repository. This reduces resource consumption since timestamped builds aren't necessary for independently published modules. |
| 86 | + |
| 87 | +## Connector design principles |
| 88 | + |
| 89 | +### One-to-one mapping |
| 90 | + |
| 91 | +Maintain a one-to-one mapping with external services whenever possible. The connector should reflect the structure and operations of the external API it wraps. |
| 92 | + |
| 93 | +For REST services, resource functions should correspond to external service resources. Combining multiple external resources into single functions is not recommended as it reduces clarity and makes the connector harder to maintain. |
| 94 | + |
| 95 | +### Design decisions |
| 96 | + |
| 97 | +Any design decisions that differ from the external system require special justification and should be documented in the specification. |
| 98 | + |
| 99 | +### Scope management |
| 100 | + |
| 101 | +It is not expected that one connector can map to multiple different APIs, even within the same system. Avoid combining multiple independent APIs into a single connector package. |
| 102 | + |
| 103 | +**Important guideline**: Systems with multiple independent REST APIs (e.g., separate sales and finance APIs within the same platform) should have separate, independent connectors rather than one package with multiple modules. Each connector should have a clear, well-defined scope aligned with a specific service or API. |
| 104 | + |
| 105 | +## Implementation approaches |
| 106 | + |
| 107 | +### REST API connectors (OAS-based) |
| 108 | + |
| 109 | +For REST API-based services, follow these steps: |
| 110 | + |
| 111 | +1. **Obtain OpenAPI specification (OAS)**: Get the OAS directly from the service provider. **Important**: It is not recommended to obtain OAS specifications from third-party providers as they may be outdated or incomplete. |
| 112 | + |
| 113 | +2. **Validate operations**: The OAS must be validated against actual API operations, as specifications often become outdated. Test all operations against the actual API to ensure correctness before proceeding. |
| 114 | + |
| 115 | +3. **Ensure examples in OAS**: The OAS must include an example request and response for each resource action. These examples are essential for mock server generation and testing. |
| 116 | + |
| 117 | +4. **Add OAS to repository**: Include the specification file in the [wso2/api-specs](https://github.com/wso2/api-specs) repository if not already present. The aligned OAS specification file against the Ballerina conventions should be added to the connector repository. Adding the specification to the repository signifies completion of validation and required modifications. |
| 118 | + |
| 119 | +5. **Generate code**: Generate Ballerina client code with resource functions (preferred) or remote functions using the OAS. If using remote functions instead of resource functions, provide justification for this decision. |
| 120 | + |
| 121 | +6. **Generate mock server**: Use the OAS to generate a mock server for testing purposes. |
| 122 | + |
| 123 | +7. **Add unit tests**: Implement unit tests to cover all connector functionality. |
| 124 | + |
| 125 | +8. **Write documentation**: Provide comprehensive documentation for users on how to use the connector, including getting started guides, examples and API references. |
| 126 | + |
| 127 | +For more information on developing OAS-based connectors, please refer to the [Create Your First Connector with Ballerina](https://ballerina.io/learn/create-your-first-connector-with-ballerina/) guide. |
| 128 | + |
| 129 | +### Handwritten connectors |
| 130 | + |
| 131 | +Handwritten connectors are used when wrapping external SDKs or when the API does not have a suitable specification. |
| 132 | + |
| 133 | +**Characteristics:** |
| 134 | +- Wrap external SDKs with Ballerina code |
| 135 | +- Typically require minimal implementation |
| 136 | +- Operations should be stateless and independent |
| 137 | +- Must include a `spec.md` file describing functionality |
| 138 | + |
| 139 | +### Specification requirements |
| 140 | + |
| 141 | +- **OAS-based connectors**: For REST API connectors, the OpenAPI Specification serves as the primary specification. Document all sanitations (modifications and alterations to the OAS) in a dedicated `sanitations.md` file within the repository. |
| 142 | + |
| 143 | +- **Handwritten connectors**: Must include a `spec.md` file that comprehensively describes all functionality and operations provided by the connector. |
| 144 | + |
| 145 | +## Testing strategy |
| 146 | + |
| 147 | +### Test necessity |
| 148 | + |
| 149 | +Tests are essential to guard against language changes and potential regressions. All connectors must include comprehensive tests. The primary reasons for testing include: |
| 150 | + |
| 151 | +- **Validating implementation against contracts**: Ensuring the connector behaves according to specifications (not common) |
| 152 | +- **Catching regression issues**: Detecting unintended changes in functionality (not common) |
| 153 | +- **Detecting breaking changes from language updates**: Identifying issues when Ballerina language is updated (relatively common) |
| 154 | +- **Validating against platforms**: Testing compatibility with GraalVM and different Java versions (not common) |
| 155 | + |
| 156 | +**Note**: Some handwritten connectors may include custom logic. In such scenarios, using tests to cover the custom logic and maintaining 80% coverage is mandatory. |
| 157 | + |
| 158 | +### Test execution |
| 159 | + |
| 160 | +- **Timing**: Run tests during releases or when we add new changes to the connector |
| 161 | +- **Coverage**: Maintain at least 80% code coverage for any custom business logic |
| 162 | + |
| 163 | +### Testing environments |
| 164 | + |
| 165 | +Prioritize testing approaches in the following order: |
| 166 | + |
| 167 | +1. **Mocking**: Mock external backends using test frameworks. |
| 168 | +2. **Docker Images**: Use containerized versions of services. |
| 169 | +3. **SaaS Connections**: Connect to actual SaaS endpoints. |
| 170 | + |
| 171 | +Mocking is preferred as it provides faster, more reliable, and cost-effective testing. |
| 172 | + |
| 173 | +## GraalVM compatibility |
| 174 | + |
| 175 | +### Pure Ballerina connectors |
| 176 | + |
| 177 | +Connectors written entirely in Ballerina are GraalVM-compatible only if all their dependencies are also compatible. |
| 178 | + |
| 179 | +### Mixed dependencies |
| 180 | + |
| 181 | +Connectors with native code or Java dependencies require: |
| 182 | +- Explicit GraalVM compatibility verification |
| 183 | +- Documentation of compatibility status |
| 184 | +- Testing with GraalVM native image builds |
| 185 | + |
| 186 | +## Observability |
| 187 | + |
| 188 | +Once a connector is developed, it is important to verify that it includes appropriate observability features for monitoring and tracing in production environments. |
| 189 | + |
| 190 | +### Metrics |
| 191 | + |
| 192 | +Connectors should implement appropriate metrics that are compatible with monitoring tools like Grafana. This enables users to track connector performance, error rates, and usage patterns in production. |
| 193 | + |
| 194 | +### Tracing |
| 195 | + |
| 196 | +Connectors should work well with distributed tracing tools like Jaeger. Proper tracing support helps users debug issues in complex integration flows and understand the full request lifecycle. |
| 197 | + |
| 198 | +### HTTP-based connectors |
| 199 | + |
| 200 | +HTTP-based connectors (those built on top of `http:Client`) already include built-in observability features through the underlying HTTP client. These connectors automatically support metrics and tracing without additional implementation. |
| 201 | + |
| 202 | +### Other connector types |
| 203 | + |
| 204 | +Connectors that are not HTTP-based (e.g., database connectors, messaging connectors) may need to explicitly add metrics and tracing information. Review the observability requirements and add any missing instrumentation. |
| 205 | + |
| 206 | +## Connector maintenance |
| 207 | + |
| 208 | +### Version management |
| 209 | + |
| 210 | +Connector versions should follow semantic versioning (SemVer) principles: |
| 211 | + |
| 212 | +- **Major Version**: Breaking changes to the API |
| 213 | +- **Minor Version**: New features, backward-compatible |
| 214 | +- **Patch Version**: Bug fixes and minor improvements |
| 215 | + |
| 216 | +### Tracking endpoint API changes |
| 217 | + |
| 218 | +Connector maintainers must actively track changes to the underlying endpoint APIs: |
| 219 | + |
| 220 | +1. **Monitor API Updates**: Regularly check for new versions or updates to the external API |
| 221 | +2. **Subscribe to Notifications**: Subscribe to API provider's changelog or release notifications |
| 222 | +3. **Review Breaking Changes**: Assess whether API changes require connector updates |
| 223 | + |
| 224 | +### Release new versions |
| 225 | + |
| 226 | +Release a new connector version whenever: |
| 227 | + |
| 228 | +- **New API Version Available**: The endpoint API releases a new version with new features or operations |
| 229 | +- **Breaking Changes**: The external API introduces breaking changes that require connector updates |
| 230 | +- **Deprecated Operations**: The API deprecates operations that need to be marked or removed |
| 231 | +- **Bug Fixes**: Issues are discovered in the connector implementation |
| 232 | +- **Security Updates**: Security vulnerabilities are identified in dependencies or the connector itself |
| 233 | + |
| 234 | +### Version release process |
| 235 | + |
| 236 | +1. **Update dependencies**: Update to the latest stable dependencies |
| 237 | +2. **Test thoroughly**: Run full test suite against the new API version |
| 238 | +3. **Update documentation**: Reflect any API changes in connector documentation |
| 239 | +4. **Update changelog**: Document all changes in the changelog |
| 240 | +5. **Tag release**: Create a git tag following the versioning scheme |
| 241 | +6. **Publish**: Publish to Ballerina Central |
| 242 | + |
| 243 | +### Backward compatibility |
| 244 | + |
| 245 | +When possible, maintain backward compatibility: |
| 246 | + |
| 247 | +- Deprecate rather than immediately remove features |
| 248 | +- Provide migration guides for breaking changes |
| 249 | + |
| 250 | +### Deprecation policy |
| 251 | + |
| 252 | +When deprecating connector features: |
| 253 | + |
| 254 | +1. Mark the feature as deprecated in the code and documentation |
| 255 | +2. Suggest alternative approaches in deprecation messages |
| 256 | +3. Update examples and documentations to use recommended patterns |
0 commit comments