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

Using dynamic schemas #72

Open
normanjaeckel opened this issue May 11, 2015 · 5 comments
Open

Using dynamic schemas #72

normanjaeckel opened this issue May 11, 2015 · 5 comments
Labels
Milestone

Comments

@normanjaeckel
Copy link

Is there an easy way to create e. g. an input schema dynamicly? At the moment the schema is loaded at import time. I would like to set an enum property an fill it with data from my database which are, as one know, not available at import time and might change later.
Example:

@schema.validate(
    input_schema={
        "type": "object",
        "properties": {
            "user": {
                "enum": [
                    ... # Put a list of all registered users here. How to do this?
                ]
            },
        },
        "required": ["user"]
    }
)
def post(self):
    ...

By the way: Thanks for this nice package again. :-)

@hfaran
Copy link
Owner

hfaran commented May 12, 2015

I believe I have an idea for this.

Have a container with API much like tornado.gen.Task, as follows:

class Callback(object):
    def __init__(self, func, *args, **kwargs):
        ...

with usage as follows (assuming there exists some function, get_users, which can query the DB/cache for list of registered users and return them):

@schema.validate(
    input_schema={
        "type": "object",
        "properties": {
            "user": {
                "enum": [
                    Callback(get_users)
                ]
            },
        },
        "required": ["user"]
    }
)
def post(self):
    ...

that would be resolved whenever this post method is called and the schema would have all Callback instances replaced with the results of func(*args, **kwargs).

Now, introducing this would make schema.validate immediately slower because it would always recurse through the schema and check for Callback instances to resolve. To avoid this, I think adding a dynamic=False kwarg to schema.validate will be added, and only if dynamic is True, will schema.validate recurse through the schema to resolve it.

So in finality, your snippet would end up looking something like:

@schema.validate(
    input_schema={
        "type": "object",
        "properties": {
            "user": {
                "enum": [
                    Callback(get_users)
                ]
            },
        },
        "required": ["user"]
    },
    dynamic=True
)
def post(self):
    ...

Does this sound reasonable?

@hfaran
Copy link
Owner

hfaran commented May 12, 2015

Implementation detail: the actual call will be done through tornado's yield gen.Task(...) pattern asynchronously.

@normanjaeckel
Copy link
Author

Ok, sounds nice. Two remarks:
Please think about that I may be want to get different properties from different sources like via AsyncHttpClient oder using Motor (with MongoDB). And maybe I have to prepare the received data in Tornado after fetching them asynchroously.
What about the api documentation? Do you want to run the callback or add just a general hint?

@hfaran
Copy link
Owner

hfaran commented May 12, 2015

Please think about that I may be want to get different properties from different sources like via AsyncHttpClient oder using Motor (with MongoDB). And maybe I have to prepare the received data in Tornado after fetching them asynchroously.

Right, so this would work if the function that did this work was called asynchronously by tornado.gen.Task, no?

class SchemaCallback(object):
    def __init__(self. func, *args, **kwargs):
        self.func = func
        self.args = args
        self.kwargs = kwargs

My idea was just to have SchemaCallback be a container class and then inside schema.validate, recurse through the schema and yield gen.Task(func, *args, **kwargs) any instances of it to resolve the full schema.

What about the api documentation? Do you want to run the callback or add just a general hint?

Maybe this could be the __str__ of the SchemaCallback?

@normanjaeckel
Copy link
Author

I am new to this so to understand everything here I must see a full example how to use may be AsyncHttpClient().fetch(...) in the function. Maybe it is really easy. Let's see.

For the documentation __str__ or even better something like get_api_documentation_content() which refers to an optional init argument and only to __str__ by default would be ok.

@hfaran hfaran added the ready label Mar 3, 2016
@hfaran hfaran added this to the 1.4.0 milestone Mar 3, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants