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

How to add a uri template pattern and control it in resource? #690

Open
truyet opened this issue Jan 20, 2016 · 7 comments
Open

How to add a uri template pattern and control it in resource? #690

truyet opened this issue Jan 20, 2016 · 7 comments

Comments

@truyet
Copy link

truyet commented Jan 20, 2016

I have a example case:

resource:
import falcon

class Resource(object):

def search(self, req, resp):
    resp.body = '{"message": "Hello world!"}'
    resp.status = falcon.HTTP_200

add resource to route
api = application = falcon.API()

api.add_route('/resource', Resource())

How to setup falcon while I request to uri: /resource/search -> redirect to function search in resource ?

@PipocaZalas
Copy link

It seems what you want is to manage your resources as MVC pattern. If you understand the principles of REST architecture and still want to implement what you asked, you could do the following:
And of course I do not recommend you do it!

class Resource:
    def __init__(self):
        self.methods = {
            'search': self._search,
        }
    def _search(self, req, resp):
        resp.body = '{"message": "Hello world!"}'
        resp.status = falcon.HTTP_200
    def on_get(self, req, resp, method):
        if method not in self.methods:
            raise falcon.HTTPNotFound()
        self.methods[method](req, resp)
api = falcon.API()
api.add_route('/resource/{method}', Resource())

@kgriffs
Copy link
Member

kgriffs commented Feb 18, 2016

As @MackYoel alluded to, what you have in mind is more along the lines of an RPC architectural style, as opposed to REST. The default router in Falcon was designed with REST in mind, with resources as the central focus, relying on a uniform interface of headers, methods (GET, POST, etc.), etc. to facilitate state transitions for those resources.

That being said, it is possible to use a custom router, but I suspect that will still require a good bit of wrangling to afford the RPC architectural style.

@kgriffs kgriffs added this to the 1.0 milestone Feb 18, 2016
@truyet
Copy link
Author

truyet commented Feb 18, 2016

Thanks @MackYoel

@kgriffs kgriffs modified the milestones: Version 1.2, Version 1.1 May 25, 2016
@kgriffs kgriffs modified the milestones: Milestone Staging, Triaged (Non-Breaking Changes) Apr 25, 2017
@goodmami
Copy link

goodmami commented Jul 6, 2019

Sorry to revive an old issue, but I didn't want to create a duplicate. Can this issue be repurposed as a feature request to add support for RPC architectures (in general, not necessarily XML-RPC or JSON-RPC)? I understand the benefits of RESTful APIs well enough but sometimes it doesn't fit. To simplify things, consider an API for a calculator: /add?x=5&y=8 seems a better fit than something like /sum/5/8.

I'm new to Falcon so please forgive my ignorance, but would this be as simple as allowing api.add_route() to target a callable instead of an object with on_get(), on_post(), etc... methods? Or is there anything wrong with something like this?

class Calculator(object):
    def on_get_add(self, req, resp):
        resp.body = str(int(req.get_param('x')) + int(req.get_param('y')))
        resp.status = falcon.HTTP_200

    def on_get_subtract(self, req, resp):
        resp.body = str(int(req.get_param('x')) - int(req.get_param('y')))
        resp.status = falcon.HTTP_200

calc = Calculator()
api = falcon.API()
api.add_route('/add', calc, suffix='add')
api.add_route('/subtract', calc, suffix='subtract')

@vytas7
Copy link
Member

vytas7 commented Jul 17, 2020

Hi @goodmami !
As of Falcon 2.0, your example does actually work as-is! We realize that the docs could better expose this feature: #1596

Regarding XML-RPC, that's usually only one end point, no routing involved 🙂

Given the above mentioned suffixes, and other new features in Falcon 2.0+, IMHO it makes sense to first of all tackle this issue (as the current label is also suggesting) from the documentation perspective, and then break out routing proposals into separate issues.

@goodmami
Copy link

@vytas7 thanks!

As of Falcon 2.0, your example does actually work as-is!

Yes, I believe it worked when I wrote it. My question is if that is an anticipated use of the suffix feature, or if it is too much a hack that it might be a discouraged pattern (and if so, why?).

Regarding XML-RPC, that's usually only one end point, no routing involved 🙂

Is there a different pattern to enable this architecture within Falcon? To be clear, I'm using Falcon already for a RESTful service, but I have an endpoint that is decidedly more RPC-like. I'd rather not use two different libraries.

IMHO it makes sense to first of [...]

Fair enough. Happy to continue the conversation on another issue.

@vytas7
Copy link
Member

vytas7 commented Jul 18, 2020

Hi again @goodmami !
And sorry for the somewhat hastily written response. I was trying to skim through all open issues we have.

Fair enough. Happy to continue the conversation on another issue.

Let me first clarify this one. It is perfectly fine to continue the conversation rolling here. What I meant was suggesting new issues in case new Falcon features were proposed to facilitate the RPC architectural style.

Yes, I believe it worked when I wrote it.

Indeed, it was already released when you wrote this... We ought to release more often 🤔

My question is if that is an anticipated use of the suffix feature, or if it is too much a hack that it might be a discouraged pattern (and if so, why?).

Regarding too much of a hack, it is ultimately only you, the API developer, who can answer this question.

The anticipated canonical use of the suffix feature is representing both a RESTful collection, and its item, with a single resource class, see, e.g., How do I implement both POSTing and GETing items for the same resource?.

Generally speaking though, the feature was added to easily afford alternate routes to the same resource. You can also find the original discussion here: #584 , as well as other issues linking to it.
In that sense, your Calculator fits that description.

To summarize, personally I think using suffixes this way is just fine. While Falcon is primarily about RESTful APIs, we also support cookies, multipart forms (coming up in 3.0), sinks, rewriting request path in middleware, rendering a complete response inside middleware, and more. None of these is strictly RESTful. In Falcon 3.0, the ASGI flavour of the framework will venture even further into the non-RESTful, enabling use cases such as SSE emitters and WebSocket.

Is there a different pattern to enable this architecture within Falcon?

As also written by @kgriffs above, another way to approach this is implementing a custom router (possibly by subclassing the default CompiledRouter). This might pay off if you happen to have existing RPC classes with a huge number of methods that you would like to expose on the routing level.

As I also hinted in my previous response though, RPC over HTTP is often implemented without even touching routing, i.e., as a single end point on POST (or even GET...). Both XML-RPC and JSON-RPC work this way. To implement them, you can just create a single Falcon responder which then translates req/resp to and from RPC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants