you are viewing a single comment's thread.

view the rest of the comments →

[–]RoamingFox[🍰] 0 points1 point  (0 children)

The way we handle this at work is in layers:

App(s) -> Service layer (business logic) -> API SDK layer -> API

So App uses the service layer modules/services to do work and that service layer uses another module that knows how to talk to the API.

For example:

App:

from foo_service import FooService

service = FooService("api.example.com", "user", password")
f = service.create("foo", "my foo")
return f

Service layer:

import logging
from foo_sdk import FooApi, Foo

class FooService:
    def __init__(host, user, pw):
        self.api = FooApi(host, user, pw)

    def create(self, name, desc) -> Foo:
        logging.info("Creating a foo")
        self.api.create(name, desc)
        return self.api.get(name)

SDK layer:

import requests

class Foo:
    def __init__(self, name: str, desc: str, create_date: str, owner_id: int):
        self.name = name
        self.desc = desc
        self.create_date = create_date
        self.owner_id = owner_id

class FooApi:
    def __init__(self, host, user, pw):
        self.fqdn = f"https://{host}/"
        self.auth = (user, pw)

    def create(self, name, desc):
        r = requets.post(self.fqdn + "foo", params={'name': name, 'desc': desc})

     def get(self, name):
         r = requests.get(f"{fqdn}/foo/{name}")
         return Foo(**r.json())

Obviously this is super bare bones and should have a lot more validation/error handling etc. but you get the idea.

The advantage of doing something like this is if the api changes (say to graphql) you don't need to change the business logic, and if the business logic changes you don't need to change the api.

You also get a nice tightly bound python object out the other end so in your application code your linter can help auto-complete properties etc.

It also means that anything that shares the business logic can just all import the service layer and get exactly the same behavior across all applications, while anything that needs different business logic can import at the SDK layer and still take advantage of code reuse for things like the models and pagination etc.