Contributing to AbacatePay Elixir SDK
View SourceThank you for your interest in contributing to the AbacatePay Elixir SDK! This guide will help you get started.
Development Setup
Prerequisites
- Elixir 1.18+ and Erlang/OTP 26+
- Git
- AbacatePay development API token
Getting Started
Fork and clone the repository
git clone https://github.com/iagocavalcante/abacatepay-elixir-sdk.git cd abacatepay-elixir-sdk
Install dependencies
mix deps.get
Set up environment variables
export ABACATEPAY_API_TOKEN="abc_dev_your_token_here" export ABACATEPAY_ENVIRONMENT="sandbox"
Run tests to ensure everything works
mix test
Code Style and Standards
Elixir Style Guide
- Follow the Elixir Style Guide
- Use
mix format
to format your code - Maximum line length: 100 characters
- Use descriptive variable and function names
Documentation
- All public functions must have
@doc
annotations - Include examples in documentation when helpful
- Use
@spec
for function specifications - Module documentation should explain the module's purpose
Example:
@doc """
Creates a new billing/invoice.
## Parameters
- `params` - Map with billing parameters:
- `:amount` - Amount in cents (integer)
- `:description` - Billing description (string)
- `:frequency` - Billing frequency: "oneTime", "monthly", "yearly" (string)
## Returns
- `{:ok, billing}` - Success with billing data
- `{:error, reason}` - Error with reason
## Examples
iex> params = %{amount: 1000, description: "Test", frequency: "oneTime"}
iex> BillingClient.create(params)
{:ok, %{"id" => "bill_123", "amount" => 1000, ...}}
"""
@spec create(map()) :: {:ok, map()} | {:error, String.t()}
def create(params) do
# Implementation
end
Testing Guidelines
Test Structure
- Write tests for all public functions
- Use descriptive test names that explain the scenario
- Group related tests with
describe/2
blocks - Use VCR cassettes for API integration tests
VCR Testing
- Record new cassettes when adding API endpoints
- Update cassettes when API responses change
- Filter sensitive data (API keys, personal info) from cassettes
- Use meaningful cassette names that describe the scenario
Example Test:
defmodule AbacatepayElixirSdk.BillingClientTest do
use ExUnit.Case
use ExVCR.Mock, adapter: ExVCR.Adapter.Finch
describe "create/1" do
test "creates billing with valid parameters" do
use_cassette "billing_create_success" do
params = %{
amount: 1000,
description: "Test billing",
frequency: "oneTime"
}
assert {:ok, billing} = BillingClient.create(params)
assert is_binary(billing["id"])
assert billing["amount"] == 1000
end
end
test "returns error with invalid parameters" do
use_cassette "billing_create_error" do
params = %{invalid: "data"}
assert {:error, _reason} = BillingClient.create(params)
end
end
end
end
Pull Request Process
Before Submitting
Run the full test suite
mix test
Format your code
mix format
Check for warnings
mix compile --warnings-as-errors
Update documentation if needed
mix docs
PR Requirements
- [ ] All tests pass
- [ ] Code follows style guidelines
- [ ] New features have tests
- [ ] Documentation is updated
- [ ] CHANGELOG.md is updated (if applicable)
- [ ] VCR cassettes are updated (if API changes)
PR Description Template
## Description
Brief description of changes made.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Added tests for new functionality
- [ ] Updated existing tests
- [ ] All tests pass
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] CHANGELOG.md updated (if needed)
API Client Guidelines
Error Handling
- Always return
{:ok, data}
or{:error, reason}
tuples - Handle all HTTP status codes appropriately
- Provide meaningful error messages
- Log errors for debugging when appropriate
HTTP Client Usage
- Use the existing
HttpClient
module for all API requests - Don't create direct HTTP calls in client modules
- Follow the established pattern for request/response handling
Example Client Implementation:
defmodule AbacatepayElixirSdk.ExampleClient do
@moduledoc """
Client for Example operations.
"""
alias AbacatepayElixirSdk.HttpClient
@doc """
Creates a new example resource.
"""
def create(params) do
case HttpClient.request(:post, "/example/create", body: Jason.encode!(params)) do
{:ok, %{status: 200, body: %{"data" => data}}} ->
{:ok, data}
{:ok, %{body: %{"error" => error}}} ->
{:error, error}
{:error, error} ->
{:error, error.reason}
end
end
end
Adding New Features
New API Endpoints
- Create a new client module in
lib/abacatepay_elixir_sdk/
- Follow the existing client pattern
- Add comprehensive tests with VCR cassettes
- Update the main module to expose the new client
- Update documentation and README
Breaking Changes
- Increment major version number
- Document migration path in CHANGELOG.md
- Add deprecation warnings before removing features
- Provide clear upgrade instructions
Reporting Issues
Bug Reports
Include:
- Elixir/Erlang versions
- SDK version
- Minimal code to reproduce the issue
- Expected vs actual behavior
- Stack trace (if applicable)
Feature Requests
Include:
- Clear description of the feature
- Use case and benefits
- Proposed API design (if applicable)
- Willingness to implement
Code Review Process
For Contributors
- Respond to feedback promptly
- Make requested changes in separate commits
- Keep discussions focused and respectful
- Ask questions when feedback is unclear
For Maintainers
- Review code for correctness, style, and design
- Test the changes locally
- Check documentation completeness
- Ensure backward compatibility
- Provide constructive feedback
Release Process
- Update version in
mix.exs
- Update
CHANGELOG.md
- Create release commit
- Tag the release
- Push to GitHub
- Publish to Hex.pm
- Update documentation
Questions?
- Create an issue for general questions
- Join our Discord for real-time discussions
- Email dev@abacatepay.com for sensitive topics
Thank you for contributing to the AbacatePay Elixir SDK! 🎉