json-rpc icon indicating copy to clipboard operation
json-rpc copied to clipboard

Add support for flask blueprints subdomains

Open biozz opened this issue 7 years ago • 1 comments

Description

Currently it is not possible to natively use flask blueprints subdomains wildcards, because JSONRPCAPI.jsonrpc method in flask backend doesn't handle additional argument if blueprint subdomain is defined as a wildcard, i.e.

    app.register_blueprint(api.as_blueprint(), subdomain='<subdomain>')

In this way, the api can be used through api.example.com or api2.example.com or other.example.com.

Steps to Reproduce

  1. Define api endpoint
  2. Register endpoint as a blueprint with wildcard subdomain
  3. Perform call to an endpoint

Expected behavior: api can be used through registered endpoint and subdomain wildcard is available in the jsonrpc method.

Actual behavior: jsonrpc raises an exception, that it can't accept additional argument, i.e. subdomain.

Reproduces how often: always

Versions

  • Ubuntu 16.04
  • Python 3.6.3
  • nginx 1.10.3 or /etc/hosts
  • json-rpc 1.10.8

Additional Information

I can see there are multiple ways this can be solved. For now I am using a workaround to handle subdomains in the application, which involves nginx and setting some headers. I would also like to contribute and make this possible, what are your thoughts on this feature?

biozz avatar Nov 29 '17 13:11 biozz

Hi! After some digging through the code I found quite simple solution to this. All I had to do was to add **kwargs into jsonrpc and jsonrpc_map methods in backend/flask, so Flask can pass the subdomain argument in.

def jsonrpc(self, **kwargs):
        request_str = self._get_request_str()
        ...

def jsonrpc_map(self, **kwargs):
        """ Map of json-rpc available calls.
        ...

That way these methods will not fail as I mentioned before:

TypeError: jsonrpc() got an unexpected keyword argument 'subdomain'
TypeError: jsonrpc_map() got an unexpected keyword argument 'subdomain'

And now subdomain name can be accessed through Flask's request.view_args inside jsonrpc method.

I can submit a PR for this, but I might need some help with the test, because it seems to fail silently.

We will need a new client, which will register blueprint with wildcard subdomain and define SERVER_NAME for the subdomains to resolve properly.

def _get_test_client_subdomain(self, api):
        @api.dispatcher.add_method
        def dummy():
            return ""

        app = Flask(__name__)
        app.config["TESTING"] = True
        app.config["SERVER_NAME"] = "example.com"
        app.register_blueprint(api.as_blueprint(), subdomain='<subdomain>')
        return app.test_client()

And the test itself, similar to test_client:

def test_subdomain(self):
        response = self.client_subdomain.post(
            '/',
            data=self.REQUEST,
            content_type='application/json',
            headers={'host': 'test.example.com'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data.decode('utf8'))
        self.assertEqual(data['result'], '')

It passes even if I put example.com in SERVER_NAME and examples.com in host headers, instead it should return Not found error when names are mismatched.

Please let me know what you think about this. I forked your repo and pushed these changes, please have a look. Thank you!

biozz avatar Jan 04 '18 16:01 biozz