Skip to content

Commit f553361

Browse files
feat(webhooks & callbacks): add contracts for webhooks and callbacks (#37)
This commit adds comprehensive contracts for webhook and callback handling by introducing a signature verification framework and HTTP request modeling. The changes enable language-agnostic webhook implementations across core libraries and SDKs. - Added signature verification interface with standardized result handling - Introduced framework-agnostic HTTP request model for webhook processing - Updated package structure and documentation to reflect new capabilities
1 parent eeb7816 commit f553361

File tree

11 files changed

+120
-30
lines changed

11 files changed

+120
-30
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,5 @@ cython_debug/
158158
# and can be added to the global gitignore or merged into this file. For a more nuclear
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160160
.idea/
161+
*.py~
162+
*~

README.md

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,47 @@
11
# apimatic-core-interfaces
2-
[![PyPI][pypi-version]](https://pypi.org/project/apimatic-core-interfaces/)
3-
[![Maintainability Rating][maintainability-badge]][maintainability-url]
4-
[![Vulnerabilities][vulnerabilities-badge]][vulnerabilities-url]
2+
[![PyPI][pypi-version]](https://pypi.org/project/apimatic-core-interfaces/)
3+
[![Maintainability Rating][maintainability-badge]][maintainability-url]
4+
[![Vulnerabilities][vulnerabilities-badge]][vulnerabilities-url]
55
[![Licence][license-badge]][license-url]
66

77
## Introduction
8-
This project contains the abstract layer for APIMatic's core library. The purpose of creating interfaces is to separate out the functionalities needed by APIMatic's core library module. The goal is to support scalability and feature enhancement of the core library and the SDKs along with avoiding any breaking changes by reducing tight coupling between modules through the introduction of interfaces.
8+
This project contains the abstract layer for APIMatic's core library. The purpose of creating interfaces is to separate out the functionalities needed by APIMatic's core library module. The goal is to support scalability and feature enhancement of the core library and the SDKs, while avoiding breaking changes by reducing tight coupling between modules.
99

10-
## Version supported
11-
Currenty APIMatic supports `Python version 3.7+` hence the apimatic-core-interfaces will need the same versions to be supported.
10+
## Version Supported
11+
Currently, APIMatic supports **Python version 3.7+**, hence the `apimatic-core-interfaces` package requires the same version support.
1212

1313
## Installation
14-
Simply run the command below in your SDK as the apimatic-core-interfaces will be added as a dependency in the SDK.
15-
```python
14+
Run the following command in your SDK (the `apimatic-core-interfaces` package will be added as a dependency):
15+
```bash
1616
pip install apimatic-core-interfaces
1717
```
1818

1919
## Interfaces
20-
| Name | Description |
21-
|-----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
22-
| [`HttpClient`](apimatic_core_interfaces/client/http_client.py) | To save both Request and Response after the completion of response |
23-
| [`ResponseFactory`](apimatic_core_interfaces/factories/response_factory.py) | To convert the client-adapter response into a custom HTTP response |
24-
| [`Authentication`](apimatic_core_interfaces/types/authentication.py) | To setup methods for the validation and application of the required authentication scheme |
25-
| [`UnionType`](apimatic_core_interfaces/types/union_type.py) | To setup methods for the validation and deserialization of OneOf/AnyOf union types |
26-
| [`Logger`](apimatic_core_interfaces/logger/logger.py) | An interface for the generic logger facade |
27-
| [`ApiLogger`](apimatic_core_interfaces/logger/api_logger.py) | An interface for logging API requests and responses |
20+
| Name | Description |
21+
|--------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
22+
| [`HttpClient`](apimatic_core_interfaces/client/http_client.py) | Saves both request and response after the completion of response. |
23+
| [`ResponseFactory`](apimatic_core_interfaces/factories/response_factory.py) | Converts the client-adapter response into a custom HTTP response. |
24+
| [`Authentication`](apimatic_core_interfaces/types/authentication.py) | Sets up methods for the validation and application of the required authentication scheme. |
25+
| [`UnionType`](apimatic_core_interfaces/types/union_type.py) | Sets up methods for the validation and deserialization of OneOf/AnyOf union types. |
26+
| [`Logger`](apimatic_core_interfaces/logger/logger.py) | An interface for the generic logger facade. |
27+
| [`ApiLogger`](apimatic_core_interfaces/logger/api_logger.py) | An interface for logging API requests and responses. |
28+
| [`SignatureVerifier`](apimatic_core_interfaces/security/signature_verifier.py) | Defines the contract for verifying the authenticity of incoming events or webhook requests. |
29+
30+
## Types
31+
| Name | Description |
32+
|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
33+
| [`Request`](apimatic_core_interfaces/http/request.py) | Framework-agnostic request model capturing headers, method, path, body, and raw bytes. |
34+
| [`SignatureVerificationResult`](apimatic_core_interfaces/types/signature_verification_result.py) | Provides a structured result of the verification process, including success, failure, and error details. |
2835

2936
## Enumerations
30-
| Name | Description |
31-
|-------------------------------------------------------------------------------|-----------------------------------------------------------------|
32-
| [`HttpMethodEnum`](apimatic_core_interfaces/types/http_method_enum.py ) | Enumeration containig HTTP Methods (GET, POST, PATCH, DELETE) |
37+
| Name | Description |
38+
|----------------------------------------------------------------------------------------|---------------------------------------------------------------|
39+
| [`HttpMethodEnum`](apimatic_core_interfaces/types/http_method_enum.py) | Enumeration containing HTTP methods (GET, POST, PATCH, DELETE).|
3340

34-
[pypi-version]: https://img.shields.io/pypi/v/apimatic-core-interfaces
35-
[license-badge]: https://img.shields.io/badge/licence-MIT-blue
36-
[license-url]: LICENSE
37-
[maintainability-badge]: https://sonarcloud.io/api/project_badges/measure?project=apimatic_core-interfaces-python&metric=sqale_rating
38-
[maintainability-url]: https://sonarcloud.io/summary/new_code?id=apimatic_core-interfaces-python
39-
[vulnerabilities-badge]: https://sonarcloud.io/api/project_badges/measure?project=apimatic_core-interfaces-python&metric=vulnerabilities
41+
[pypi-version]: https://img.shields.io/pypi/v/apimatic-core-interfaces
42+
[license-badge]: https://img.shields.io/badge/licence-MIT-blue
43+
[license-url]: LICENSE
44+
[maintainability-badge]: https://sonarcloud.io/api/project_badges/measure?project=apimatic_core-interfaces-python&metric=sqale_rating
45+
[maintainability-url]: https://sonarcloud.io/summary/new_code?id=apimatic_core-interfaces-python
46+
[vulnerabilities-badge]: https://sonarcloud.io/api/project_badges/measure?project=apimatic_core-interfaces-python&metric=vulnerabilities
4047
[vulnerabilities-url]: https://sonarcloud.io/summary/new_code?id=apimatic_core-interfaces-python

apimatic_core_interfaces/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
'client',
33
'factories',
44
'types',
5-
'logger'
6-
]
5+
'logger',
6+
'http',
7+
'security'
8+
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__all__ = [
2+
'request',
3+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from dataclasses import dataclass, field
2+
from typing import Dict, List, Optional
3+
4+
@dataclass(frozen=True)
5+
class Request:
6+
"""Framework-agnostic HTTP request snapshot (files excluded)."""
7+
method: str
8+
path: str
9+
url: Optional[str]
10+
headers: Dict[str, str]
11+
raw_body: bytes
12+
query: Dict[str, List[str]] = field(default_factory=dict)
13+
cookies: Dict[str, str] = field(default_factory=dict)
14+
form: Dict[str, List[str]] = field(default_factory=dict)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__all__ = [
2+
'signature_verifier'
3+
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from abc import ABC, abstractmethod
2+
3+
from apimatic_core_interfaces.http.request import Request
4+
from apimatic_core_interfaces.types.signature_verification_result import SignatureVerificationResult
5+
6+
7+
class SignatureVerifier(ABC):
8+
"""
9+
Abstract base class for signature verification.
10+
11+
Implementations must validate that the provided JSON payload matches
12+
the signature contained in the headers.
13+
"""
14+
15+
@abstractmethod
16+
def verify(self, request: Request) -> SignatureVerificationResult:
17+
"""
18+
Perform signature verification.
19+
20+
Returns:
21+
SignatureVerificationResult: ok=True when the signature is valid; ok=False with the
22+
underlying exception (if any) when invalid or an error occurred.
23+
24+
Notes:
25+
Implementations should NOT raise for runtime verification outcomes; return
26+
VerificationResult.failed(error) instead. Reserve raising for programmer
27+
errors (invalid construction/config).
28+
"""
29+
raise NotImplementedError
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
__all__ = [
22
'http_method_enum',
33
'authentication',
4-
'union_type'
4+
'union_type',
5+
'signature_verification_result'
56
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import annotations
2+
from typing import Optional, List
3+
4+
5+
class SignatureVerificationResult:
6+
"""
7+
Outcome of signature verification.
8+
9+
Attributes:
10+
ok: True if the signature verification passed.
11+
errors: Optional list of errors raised by the verifier. None when ok=True.
12+
"""
13+
ok: bool
14+
errors: Optional[List[str]] = None
15+
16+
def __init__(self, ok: bool, errors: Optional[List[str]] = None):
17+
self.ok = ok
18+
self.errors = errors
19+
20+
@staticmethod
21+
def passed() -> "SignatureVerificationResult":
22+
return SignatureVerificationResult(ok=True, errors=None)
23+
24+
@staticmethod
25+
def failed(errors: Optional[List[str]] = None) -> "SignatureVerificationResult":
26+
return SignatureVerificationResult(ok=False, errors=errors)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
setup(
1414
name='apimatic-core-interfaces',
15-
version='0.1.6',
15+
version='0.1.7',
1616
description='An abstract layer of the functionalities provided by apimatic-core-library, requests-client-adapter '
1717
'and APIMatic SDKs.',
1818
long_description=long_description,

0 commit comments

Comments
 (0)