Skip to content

Commit

Permalink
Fixed SIGECA API client (#4)
Browse files Browse the repository at this point in the history
* Fixed SIGECA API client

* Removed print statement
  • Loading branch information
malinowskikam authored Jun 19, 2024
1 parent ed425f9 commit 40d9c35
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List
from apscheduler.schedulers.background import BlockingScheduler
from app.application.services.sigeca_data_export_service import DataSyncService
from app.infrastructure.api import ResourceAPIClient
from app.infrastructure.api import SigecaApiClient
from app.infrastructure.utils import ChangeLogOperationEnum
from sqlalchemy.orm import sessionmaker
from app.infrastructure.repository import SyncLogRepository
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .jdbc_reader import JDBCReader
from .utils import ChangeLogOperationEnum
from .api import ResourceAPIClient
from .api import SigecaApiClient
65 changes: 52 additions & 13 deletions sigeca_data_export_microservice/app/infrastructure/api.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
import requests
from typing import Any, Dict
from .utils import ChangeLogOperationEnum
import logging


class ResourceAPIClient:
def __init__(self, api_url: str, token: str):
class SigecaApiClient:
LOGIN_URI = "token/"
SYNC_URI = "sync/"

def __init__(self, api_config: dict):
api_url: str = api_config["api_url"]
headers: str = api_config["headers"]
self.credentials = api_config['credentials']
self.skip_verification: bool = api_config.get('skip_verification') or False

if api_url.endswith("/"):
api_url = api_url[:-1]

self.api_url = api_url
self.token = token
self.headers = {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json",
# Required for avoid openLMIS 401 Unauthorized during login
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0",
**headers,
}

def send_data(
self, resource: str, operation: ChangeLogOperationEnum, data: Dict[str, Any]
) -> Dict[str, Any]:
endpoint = f"{self.api_url}/{resource}/{operation.value}"
response = requests.post(endpoint, json=data, headers=self.headers)
return response.json()
def sync(self, json_data=None):
if not isinstance(json_data, list):
logging.error(
f"Attempt to sync invalid payload: {json_data}"
)
raise Exception("Attempt to sync invalid payload")

self._get_token()
url = f"{self.api_url}/{self.SYNC_URI}"

response = requests.post(url, json=json_data, headers=self.headers, verify=not self.skip_verification)

if response.status_code == 200:
return True
else:
logging.error(
f"Failed to sync data with sigeca central API: {response.status_code} {response}"
)
raise Exception("Failed to sync data with sigeca central API")

def _get_token(self):
"""Login to get access token"""
url = f"{self.api_url}/{self.LOGIN_URI}"
data = self.credentials

response = requests.post(url, headers=self.headers, data=data, verify=not self.skip_verification)

if response.status_code == 200:
self.token = response.json().get("access_token")
self.headers['Authorization'] = F"Bearer {self.token}"
else:
logging.error(
f"Failed to log into OpenLMIS API: {response.status_code} {response}"
)
raise Exception("Failed to log into sigeca central API")
35 changes: 20 additions & 15 deletions sigeca_data_export_microservice/config_example.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
{
"api": {
"url": "https://api.example.com", // URL of the external API to which data will be synchronized
"token": "your_api_token" // Authentication token for accessing the external API
"sigeca_api" : {
"api_url": "https://example.com/api",
"headers": {},
"credentials": {
"username": "username",
"password": "password"
},
"skip_verification": false
},
"changelog_database": {
"username": "user1", // Username for the database used to store synchronization logs
"password": "password1", // Password for the database user
"host": "localhost", // Hostname or IP address of the database server
"port": 5432, // Port number on which the database server is listening
"database": "database" // Name of the database
"username": "user1",
"password": "password1",
"host": "localhost",
"port": 5432,
"database": "database"
},
"jdbc_reader": {
"jdbc_url": "jdbc:postgresql://localhost:5432/database", // JDBC URL for connecting to the database
"jdbc_user": "user1", // Username for the database used by JDBC Reader
"jdbc_password": "password1", // Password for the database user used by JDBC Reader
"jdbc_driver": "org.postgresql.Driver", // JDBC driver class for PostgreSQL
"log_level": "INFO" // Log level for JDBC operations (e.g., INFO, DEBUG)
"jdbc_reader": {
"jdbc_url": "jdbc:postgresql://localhost:5432/database",
"jdbc_user": "user1",
"jdbc_password": "password1",
"jdbc_driver": "org.postgresql.Driver",
"log_level": "INFO"
},
"sync": {
"interval_minutes": 0.2 // Synchronization interval in minutes (0.2 minutes = 12 seconds for quick testing)
"interval_minutes": 0.2
}
}
4 changes: 2 additions & 2 deletions sigeca_data_export_microservice/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from app.application.scheduler.sigeca_data_export_scheduler import ChangesSyncScheduler
from app.application.synchronizations import FacilityResourceSynchronization
from app.infrastructure import (ChangeLogOperationEnum, JDBCReader,
ResourceAPIClient)
SigecaApiClient)
from app.infrastructure.database import Base, get_engine, get_session


Expand Down Expand Up @@ -46,7 +46,7 @@ def main():
Base.metadata.create_all(engine)

jdbc_reader = JDBCReader(config["jdbc_reader"])
api_client = ResourceAPIClient(config["api"]["url"], config["api"]["token"])
api_client = SigecaApiClient(config["sigeca_api"])
sigeca_data_export_service = DataSyncService(session_maker)

sync_interval_minutes = config["sync"]["interval_minutes"]
Expand Down

0 comments on commit 40d9c35

Please sign in to comment.