Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Setup API client #1

Merged
merged 7 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Lago Python Client

This is a python wrapper for Lago API

## Installation

Install the lago-python-client via pip from PyPI:

$ pip install lago-python-client

## Usage

``` python
from lago_python_client import Client

client = Client(api_key = 'key')
```

### Events
[Api reference](https://doc.getlago.com/docs/api/events)

``` python
from lago_python_client.models import Event

event = Event(
customer_id="5eb02857-a71e-4ea2-bcf9-57d8885990ba",
transaction_id="__UNIQUE_ID__",
code="123",
transaction_id="123",
timestamp=1650893379,
properties={"custom_field": "custom"}
)

client.events().create(event)
```

### Customers
[Api reference](https://doc.getlago.com/docs/api/customers/customer-object)

``` python
from lago_python_client.models import Customer

customer = Customer(
customer_id="5eb02857-a71e-4ea2-bcf9-57d8885990ba",
address_line1=None,
address_line2=None,
city=None,
country=None,
email="test@example.com",
legal_name=None,
legal_number=None,
logo_url=None,
name="test name",
phone=None,
state=None,
url=None,
vat_rate=None,
zipcode=None
)
client.customers().create(customer)
```

### Subscriptions
[Api reference](https://doc.getlago.com/docs/api/subscriptions/subscription-object)

``` python
from lago_python_client.models import Subscription

subscription = Subscription(
customer_id="5eb02857-a71e-4ea2-bcf9-57d8885990ba",
plan_code="code"
)
client.subscriptions().create(subscription)

params_delete = {
"customer_id": "5eb02857-a71e-4ea2-bcf9-57d8885990ba"
}
client.subscriptions().delete(params_delete)
```
1 change: 1 addition & 0 deletions lago_python_client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from lago_python_client.client import Client
28 changes: 28 additions & 0 deletions lago_python_client/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from lago_python_client.clients.subscription_client import SubscriptionClient
from lago_python_client.clients.customer_client import CustomerClient
from lago_python_client.clients.event_client import EventClient
from urllib.parse import urljoin


class Client:
BASE_URL = 'https://api.getlago.com/'
API_PATH = 'api/v1/'

def __init__(self, api_key: str = None, api_url: str = None):
self.api_key = api_key
self.api_url = api_url

def base_api_url(self):
if self.api_url is None:
return urljoin(Client.BASE_URL, Client.API_PATH)
else:
return urljoin(self.api_url, Client.API_PATH)

def events(self):
return EventClient(self.base_api_url(), self.api_key)

def subscriptions(self):
return SubscriptionClient(self.base_api_url(), self.api_key)

def customers(self):
return CustomerClient(self.base_api_url(), self.api_key)
3 changes: 3 additions & 0 deletions lago_python_client/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from lago_python_client.clients.event_client import EventClient
from lago_python_client.clients.subscription_client import SubscriptionClient
from lago_python_client.clients.customer_client import CustomerClient
60 changes: 60 additions & 0 deletions lago_python_client/clients/base_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import requests
import json

from pydantic import BaseModel
from requests import Response
from typing import Dict
from urllib.parse import urljoin


def handle_response(response: Response):
if response.status_code in BaseClient.RESPONSE_SUCCESS_CODES:
if response.text:
return response.json()
else:
return None
else:
raise LagoApiError(
"URI: %s. Status code: %s. Response: %s." % (
response.request.url, response.status_code, response.text)
)


class BaseClient:
RESPONSE_SUCCESS_CODES = [200, 201, 202, 204]

def __init__(self, base_url: str, api_key: str):
self.base_url = base_url
self.api_key = api_key

def create(self, input_object: BaseModel):
query_url = urljoin(self.base_url, self.api_resource())
query_parameters = {
self.root_name(): input_object.dict()
}
data = json.dumps(query_parameters)
api_response = requests.post(query_url, data=data, headers=self.headers())
data = handle_response(api_response)

if data is None:
return True
else:
return self.prepare_response(data.get(self.root_name()))

def delete(self, params: Dict):
query_url = urljoin(self.base_url, self.api_resource())
data = json.dumps(params)
api_response = requests.delete(query_url, data=data, headers=self.headers())
data = handle_response(api_response).get(self.root_name())

return self.prepare_response(data)

def headers(self):
bearer = "Bearer " + self.api_key
headers = {'Content-type': 'application/json', 'Authorization': bearer}

return headers


class LagoApiError(Exception):
...
14 changes: 14 additions & 0 deletions lago_python_client/clients/customer_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .base_client import BaseClient
from lago_python_client.models.customer import ResponseCustomer
from typing import Dict


class CustomerClient(BaseClient):
def api_resource(self):
return 'customers'

def root_name(self):
return 'customer'

def prepare_response(self, data: Dict):
return ResponseCustomer.parse_obj(data)
9 changes: 9 additions & 0 deletions lago_python_client/clients/event_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .base_client import BaseClient


class EventClient(BaseClient):
def api_resource(self):
return 'events'

def root_name(self):
return 'event'
14 changes: 14 additions & 0 deletions lago_python_client/clients/subscription_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .base_client import BaseClient
from lago_python_client.models.subscription import ResponseSubscription
from typing import Dict


class SubscriptionClient(BaseClient):
def api_resource(self):
return 'subscriptions'

def root_name(self):
return 'subscription'

def prepare_response(self, data: Dict):
return ResponseSubscription.parse_obj(data)
3 changes: 3 additions & 0 deletions lago_python_client/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from lago_python_client.models.event import Event
from lago_python_client.models.customer import Customer
from lago_python_client.models.subscription import Subscription
40 changes: 40 additions & 0 deletions lago_python_client/models/customer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from pydantic import BaseModel, Field
from typing import Optional


class Customer(BaseModel):
customer_id: str
address_line1: Optional[str]
address_line2: Optional[str]
city: Optional[str]
country: Optional[str]
email: Optional[str]
legal_name: Optional[str]
legal_number: Optional[str]
logo_url: Optional[str]
name: str
phone: Optional[str]
state: Optional[str]
url: Optional[str]
vat_rate: Optional[float]
zipcode: Optional[str]


class ResponseCustomer(BaseModel):
vincent-pochet marked this conversation as resolved.
Show resolved Hide resolved
lago_id: str
customer_id: str
address_line1: Optional[str]
address_line2: Optional[str]
city: Optional[str]
country: Optional[str]
email: Optional[str]
created_at: str
legal_name: Optional[str]
legal_number: Optional[str]
logo_url: Optional[str]
name: str
phone: Optional[str]
state: Optional[str]
url: Optional[str]
vat_rate: Optional[float]
zipcode: Optional[str]
10 changes: 10 additions & 0 deletions lago_python_client/models/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import BaseModel, Field
from typing import Optional


class Event(BaseModel):
transaction_id: str
customer_id: str
code: str
timestamp: Optional[int]
properties: Optional[dict]
19 changes: 19 additions & 0 deletions lago_python_client/models/subscription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pydantic import BaseModel, Field
from typing import Optional


class Subscription(BaseModel):
plan_code: str
customer_id: str


class ResponseSubscription(BaseModel):
lago_id: str
lago_customer_id: Optional[str]
customer_id: Optional[str]
canceled_at: Optional[str]
created_at: Optional[str]
plan_code: Optional[str]
started_at: Optional[str]
status: Optional[str]
terminated_at: Optional[str]
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ packages = find:
python_requires = >=3.6
install_requires =
requests==2.26.0
pydantic
requests-mock
4 changes: 4 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from tests.test_event_client import TestEventClient
from tests.test_subscription_client import TestSubscriptionClient
from tests.test_customer_client import TestCustomerClient
from tests.test_client import TestClient
21 changes: 21 additions & 0 deletions tests/fixtures/customer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"customer": {
"lago_id": "99a6094e-199b-4101-896a-54e927ce7bd7",
"customer_id": "5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba",
"address_line1": "5230 Penfield Ave",
"address_line2": null,
"city": "Woodland Hills",
"country": "US",
"created_at": "2022-04-29T08:59:51Z",
"email": "dinesh@piedpiper.test",
"legal_name": "Coleman-Blair",
"legal_number": "49-008-2965",
"logo_url": "http://hooli.com/logo.png",
"name": "Gavin Belson",
"phone": "1-171-883-3711 x245",
"state": "CA",
"url": "http://hooli.com",
"vat_rate": 12.5,
"zipcode": "91364"
}
}
13 changes: 13 additions & 0 deletions tests/fixtures/subscription.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"subscription": {
"lago_id": "b7ab2926-1de8-4428-9bcd-779314ac129b",
"lago_customer_id": "99a6094e-199b-4101-896a-54e927ce7bd7",
"customer_id": "5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba",
"canceled_at": "2022-04-29T08:59:51Z",
"created_at": "2022-04-29T08:59:51Z",
"plan_code": "eartha lynch",
"started_at": "2022-04-29T08:59:51Z",
"status": "active",
"terminated_at": null
}
}
20 changes: 20 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import unittest

from lago_python_client.client import Client


class TestClient(unittest.TestCase):
def test_base_url_when_api_url_is_given(self):
client = Client(api_key='886fe239-927d-4072-ab72-6dd345e8dd0d',
api_url='https://example.com/')

self.assertEqual(client.base_api_url(), 'https://example.com/api/v1/')

def test_base_url_when_api_url_is_not_given(self):
client = Client(api_key='886fe239-927d-4072-ab72-6dd345e8dd0d')

self.assertEqual(client.base_api_url(), 'https://api.getlago.com/api/v1/')


if __name__ == '__main__':
unittest.main()
Loading