The Controller is the heart of Endpoints. Every request will go through a controller class.
Create a file named controllers.py with the following contents:
from endpoints import Controller
class Hello(Controller):
async def GET(self):
return "hello world"Now you can make a request:
$ curl http://localhost:8000/hello
"hello world"
Now let's try some different stuff:
$ curl http://localhost:8000/hello -d "name=Alice"
{"errno": 501, "errmsg": "POST /hello not implemented"}
We received a 501 response because our Hello controller has no POST method, let's add one:
from endpoints import Controller
class Hello(Controller):
async def GET(self):
return "hello world"
async def POST(self, name: str):
return "hello {}".format(name)Let's see if it worked:
$ curl http://localhost:8000/hello -d "name=Alice"
"hello Alice"
You can define your controller methods to accept certain path params and to accept query params:
class Foo(Controller):
async def GET(self, one, two=None, **params): pass
async def POST(self, **params): passyour call requests would be translated like this:
| HTTP Request | Path Followed |
|---|---|
| GET /foo/one | controllers.Default.GET() |
| GET /foo/one?param1=val1¶m2=val2 | controllers.Foo.GET("one", param1="val1", param2="val2") |
| GET /foo | 405, no one path param to pass to GET |
| GET /foo/one/two | controllers.Foo.GET("one", "two") |
Post requests are also merged with the **params on the controller method, with the POST params taking precedence:
For example, if the HTTP request is:
POST /foo?param1=GET1¶m2=GET2 with body: param1=POST1¶m3=val3
The following path would be:
prefix.Foo.POST(param1="POST1", param2="GET2", param3="val3")
Every Endpoints Controller can activate Cors support. This support will handle all the OPTION requests, and setting all the appropriate headers, so you don't have to worry about them (unless you want to).
from endpoints import Controller, CORSMixin
class Default(Controller, CORSMixin):
async def GET(self):
return "This will have CORS support"If a suitable controller can't be found using the path then Endpoints will default to a Controller class named Default.
For example:
# controllers.py
from endpoints import Controller
class Default(Controller):
async def GET(self, *args, **kwargs):
return "GET {}".format("/".join(args))
async def POST(self, *args, **kwargs):
return "POST {}".format("/".join(args))The request:
POST /foo/bar
would be handled by controllers.Default and return:
POST foo/bar
This makes it possible for you to define your paths in multiple different ways, for example:
#controllers.py
from endpoints import Controller
class User(Controller):
async def GET(self): passcould be equivalent to:
# controllers/user.py
from endpoints import Controller
class Default(Controller):
async def GET(self): passEndpoints first checks module paths, then it checks classes in the found module, then defaults to the Default class if no other suitable class is found.
Imagine a folder structure like this:
controllers/
__init__.py
foo.py
With controllers/__init__.py having content:
from endpoints import Controller
class Default(Controller):
async def GET(self, *args, **kwargs):
passAnd controllers/foo.py having content:
from endpoints import Controller
class Default(Controller):
async def GET(self, *args, **kwargs):
pass
class Bar(Controller):
async def GET(self, *args, **kwargs):
pass
async def POST(self, *args, **kwargs):
passBelow are how the HTTP requests would be interpreted using endpoints using controllers as the prefix.
| HTTP Request | Path Followed |
|---|---|
| GET / | controllers.Default.GET() |
| GET /foo | controllers.foo.Default.GET() |
| POST /foo/bar | controllers.foo.Bar.POST() |
| GET /foo/bar/che | controllers.foo.Bar.GET(che) |
| GET /foo/bar/che?baz=foo | controllers.foo.Bar.GET(che, baz=foo) |
| POST /foo/bar/che with body: baz=foo | controllers.foo.Bar.POST(che, baz=foo) |