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

ORM Query over API #8

Open
mreschke opened this issue Mar 24, 2021 · 0 comments
Open

ORM Query over API #8

mreschke opened this issue Mar 24, 2021 · 0 comments
Assignees
Labels
enhancement New feature or request orm ORM package
Milestone

Comments

@mreschke
Copy link
Member

mreschke commented Mar 24, 2021

All ORM model queries like User.query().get() should be able to query the local database OR switch to remote API mode and the query will be converted to a aiohttp request.

The goal is to pull this off without a syntax change. If you had to change syntax, this wouldn't work. All you should have to do is change your database config from local MySQL to remote uvicore_api. No code change.

How can we possibly do this? The complication is that when using remote mode, the aiohttp request needs an authentication token. This token can come from a controller route or from some backend ~/.config/myapp.json file during CLI "login" command. Either way, the ORM query must know about this token somehow.

Examples:

From a controller. The route already has the request, and the authorization or www basic auth header is already there. So we need to get it into the ORM query

user = IamUser.query(request).include('tenant').get()

The query() method will see a request and only if config remote=true will it grab the authorization or www headers and pass them into the API QueryBuilder for aiohttp usage. If config remote=false, this variable is ignored. This means the code is consistent, and doesn't change. It feels odd if you never need to use remote=true, but if you ever do, code does not need to change.

From some command line where the token is in a ~/.config/myapp.json file

user = IamUser.query().include('tenant').get()

Notice nothing in query()? You can override query() with your own and if remote=true then look up token in ~/.config and inject it. If remote=false, just ORM local as usual.

All of this means that your remote API must be able to use the same TOKEN as the one you are currently using. Lets say we have a tools CLI app. You run ./uvicore tools login and enter user/pass, it calls remote IDP gets token, stores token in ~/.config. Your tools app wants to query a remote IAM uvicore app. That IAM API must also understand the current Tools token. This works fine if you own both APIs and both authenticate with the same token. You are just passing whatever auth method in Tools on to IAM. If they don't use the same token, Tools would have to "login" to IAM's IDP as well and store an IAM compatible token to pass through, which wouldn't be in the request header. So your query() override needs to be able to handle all this work.

Also, if a middleware could pull out your authorization token, store in a common location (some constant variable), then you wouldn't need to pass request into query(request) at all! Just plain old User.query().get() would still work. Override the query() method and search for an auth header in your special place, or if from CLI, use ~/.config... NO probably not, its not per user, your token storage would get clobbered.

Here are some notes I had in a py file

            # Cross api usage
            # Lets say this is TOOLS app and I want to query IAM from IAM API
            token = request.headers.get('Authorization') # MINUS bearer

            # So this is an API SDK helper.  It GET on a URL
            # and passes in existing TOOLS token, which should work in IAM too
            # Token must be passed around, which means I cannot query IAM from a non logged in
            # CLI app.  I always need a FA token.  So even CLI apps and cron tasks need a login
            # to get an access token.
            user = iam.get('/sun/users/1', token)

            # Could work, but model would need to know its in local DB mode
            # or remote API mode.
            user = IAMUser.query(token).include('tenant').get()

            # Or add a api() method on the model that has its own query builder COPY for APIs
            # This is a uvicore specific API query builder
            user = IAMUser.api(token).include('tenant').get()

            # If using basic auth
            user = IAMUser.api(username=username, password=password).include('tenant').get()

            # Or to keep query identical, do a login first and get new logged in instance
            # presenes of a login would swap from local ORM mode to remote API mode?
            User = IAMUser.login(token) # Login function could look at a CONFIG for remote=true, if false ignore login use ORM
            user = User.query().include('tenant').get()

            # Or all in one I suppose same thing
            user = IAMUser.login(token).query().include('tanant').get()

            # Guess the query() itself could detect the login, only if config remote=true
            user = IAMUser.query(token).include('tenant').get()

            # Maybe you can set a token for ALL models in this request
            Iam.login(token)  # though if not instance, will collide with multiple user requests
            user = IAMUser.query().include('tanent').get()
            app = IAMApp.query().get()
@mreschke mreschke added enhancement New feature or request orm ORM package labels Mar 24, 2021
@mreschke mreschke added this to the v1.0 Release milestone Mar 24, 2021
@mreschke mreschke self-assigned this Mar 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request orm ORM package
Projects
None yet
Development

No branches or pull requests

1 participant