Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method GET, POST, PUT or DELETE (other methods are not suported yet).
Each route can have one or more handler methods, which are executed when the route is matched.
Route handlers definition takes the following form:
class MyHandler
super Handler
redef fun METHOD(req, res) do end
end
Where:
MyHandler
is the name of the handler you will add to the app.METHOD
can be replaced by get
, post
, put
or delete
.The following example responds with Hello World!
to GET and POST requests:
class MyHandler
super Handler
redef fun get(req, res) do res.send "Got a GET request"
redef fun post(req, res) do res.send "Got a POST request"
end
To make your handler responds to a specific route, you have to add it to the app.
Respond to POST request on the root route (/
), the application's home page:
var app = new App
app.use("/", new MyHandler)
Respond to a request to the /user
route:
app.use("/user", new MyHandler)
popcorn :: Handler :: defaultinit
popcorn :: Handler :: deserialize_body
Deserialize the request bodypopcorn :: Handler :: validate_body
Validate body input withvalidator
popcorn :: Handler :: validator
Validator used to check body inputpopcorn :: Handler :: validator=
Validator used to check body inputcore :: Object :: class_factory
Implementation used byget_class
to create the specific class.
popcorn :: Handler :: defaultinit
core :: Object :: defaultinit
popcorn :: Handler :: deserialize_body
Deserialize the request bodycore :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
core :: Object :: output_class_name
Display class name on stdout (debug only).popcorn :: Handler :: validate_body
Validate body input withvalidator
popcorn :: Handler :: validator
Validator used to check body inputpopcorn :: Handler :: validator=
Validator used to check body inputpopcorn :: GithubOAuthCallBack
Get the authentification code and translate it to an access token.
# Class handler for a route.
#
# **Routing** refers to determining how an application responds to a client request
# to a particular endpoint, which is a URI (or path) and a specific HTTP request
# method GET, POST, PUT or DELETE (other methods are not suported yet).
#
# Each route can have one or more handler methods, which are executed when the route is matched.
#
# Route handlers definition takes the following form:
#
# ~~~nitish
# class MyHandler
# super Handler
#
# redef fun METHOD(req, res) do end
# end
# ~~~
#
# Where:
# * `MyHandler` is the name of the handler you will add to the app.
# * `METHOD` can be replaced by `get`, `post`, `put` or `delete`.
#
# The following example responds with `Hello World!` to GET and POST requests:
#
# ~~~
# class MyHandler
# super Handler
#
# redef fun get(req, res) do res.send "Got a GET request"
# redef fun post(req, res) do res.send "Got a POST request"
# end
# ~~~
#
# To make your handler responds to a specific route, you have to add it to the app.
#
# Respond to POST request on the root route (`/`), the application's home page:
#
# ~~~
# var app = new App
# app.use("/", new MyHandler)
# ~~~
#
# Respond to a request to the `/user` route:
#
# ~~~
# app.use("/user", new MyHandler)
# ~~~
abstract class Handler
# Call `all(req, res)` if `route` matches `uri`.
private fun handle(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse) do
if route.match(uri) then
if route isa AppParamRoute then
req.uri_params = route.parse_uri_parameters(uri)
end
all(req, res)
end
end
# Handler to all kind of HTTP request methods.
#
# `all` is a special request handler, which is not derived from any
# HTTP method. This method is used to respond at a path for all request methods.
#
# In the following example, the handler will be executed for requests to "/user"
# whether you are using GET, POST, PUT, DELETE, or any other HTTP request method.
#
# ~~~
# class AllHandler
# super Handler
#
# redef fun all(req, res) do res.send "Every request to the homepage"
# end
# ~~~
#
# Using the `all` method you can also implement other HTTP request methods.
#
# ~~~
# class MergeHandler
# super Handler
#
# redef fun all(req, res) do
# if req.method == "MERGE" then
# # handle that method
# else super # keep handle GET, POST, PUT and DELETE methods
# end
# end
# ~~~
fun all(req: HttpRequest, res: HttpResponse) do
if req.method == "GET" then
get(req, res)
else if req.method == "POST" then
post(req, res)
else if req.method == "PUT" then
put(req, res)
else if req.method == "DELETE" then
delete(req, res)
else
res.status_code = 405
end
end
# GET handler.
#
# Exemple of route responding to GET requests.
# ~~~
# class GetHandler
# super Handler
#
# redef fun get(req, res) do res.send "GETrequest received"
# end
# ~~~
fun get(req: HttpRequest, res: HttpResponse) do end
# POST handler.
#
# Exemple of route responding to POST requests.
# ~~~
# class PostHandler
# super Handler
#
# redef fun post(req, res) do res.send "POST request received"
# end
# ~~~
fun post(req: HttpRequest, res: HttpResponse) do end
# PUT handler.
#
# Exemple of route responding to PUT requests.
# ~~~
# class PutHandler
# super Handler
#
# redef fun put(req, res) do res.send "PUT request received"
# end
# ~~~
fun put(req: HttpRequest, res: HttpResponse) do end
# DELETE handler.
#
# Exemple of route responding to PUT requests.
# ~~~
# class DeleteHandler
# super Handler
#
# redef fun delete(req, res) do res.send "DELETE request received"
# end
# ~~~
fun delete(req: HttpRequest, res: HttpResponse) do end
end
lib/popcorn/pop_handlers.nit:23,1--172,3
redef class Handler
# Validator used to check body input
#
# Here we use the `pop_validation` module to validate JSON document from the request body.
var validator: nullable DocumentValidator = null
# Validate body input with `validator`
#
# Try to validate the request body as a json document using `validator`:
# * Returns the validated string input if the result of the validation is ok.
# * Answers a json error and returns `null` if something went wrong.
# * If no `validator` is set, returns the body without validation.
#
# Example:
#
# ~~~nit
# class ValidatedHandler
# super Handler
#
# redef var validator = new MyObjectValidator
#
# redef fun post(req, res) do
# var body = validate_body(req, res)
# if body == null then return # Validation error
# # At this point popcorn returned a HTTP 400 code with the validation error
# # if the validation failed.
#
# # TODO do something with the input
# print body
# end
# end
#
# class MyObjectValidator
# super ObjectValidator
#
# init do
# add new StringField("name", min_size=1, max_size=255)
# end
# end
# ~~~
fun validate_body(req: HttpRequest, res: HttpResponse): nullable String do
var body = req.body
var validator = self.validator
if validator == null then return body
if not validator.validate(body) then
res.json(validator.validation, 400)
return null
end
return body
end
# Deserialize the request body
#
# Returns the deserialized request body body or `null` if something went wrong.
# If the object cannot be deserialized, answers with a HTTP 400.
#
# See `BODY` and `new_body_object`.
#
# Example:
# ~~~nit
# class MyDeserializedHandler
# super Handler
#
# redef type BODY: MyObject
#
# redef fun post(req, res) do
# var form = deserialize_body(req, res)
# if form == null then return # Deserialization error
# # At this point popcorn returned a HTTP 400 code if something was wrong with
# # the deserialization process
#
# # TODO do something with the input
# print form.name
# end
# end
#
# class MyObject
# serialize
#
# var name: String
# end
# ~~~
fun deserialize_body(req: HttpRequest, res: HttpResponse): nullable BODY do
var body = req.body
var deserializer = new JsonDeserializer(body)
var form = deserializer.deserialize(body_type)
if not form isa BODY or deserializer.errors.not_empty then
res.json_error("Bad input", 400)
return null
end
return form
end
# Kind of objects returned by `deserialize_body`
#
# Define it in each sub handlers depending on the kind of objects sent in request bodies.
type BODY: Serializable
private var body_type: String is lazy do return (new GetName[BODY]).to_s
end
lib/popcorn/pop_json.nit:63,1--165,3