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:

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)

Introduced properties

type BODY: Serializable

popcorn :: Handler :: BODY

Kind of objects returned by deserialize_body
private var _body_type: String

popcorn :: Handler :: _body_type

private var _validator: nullable DocumentValidator

popcorn :: Handler :: _validator

Validator used to check body input
fun all(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: all

Handler to all kind of HTTP request methods.
private fun body_type: String

popcorn :: Handler :: body_type

private fun body_type=(body_type: String)

popcorn :: Handler :: body_type=

fun delete(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: delete

DELETE handler.
fun deserialize_body(req: HttpRequest, res: HttpResponse): nullable BODY

popcorn :: Handler :: deserialize_body

Deserialize the request body
fun get(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: get

GET handler.
private fun handle(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: handle

Call all(req, res) if route matches uri.
fun post(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: post

POST handler.
fun put(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: put

PUT handler.
fun validate_body(req: HttpRequest, res: HttpResponse): nullable String

popcorn :: Handler :: validate_body

Validate body input with validator
fun validator: nullable DocumentValidator

popcorn :: Handler :: validator

Validator used to check body input
protected fun validator=(validator: nullable DocumentValidator)

popcorn :: Handler :: validator=

Validator used to check body input

Redefined properties

redef type SELF: Handler

popcorn $ Handler :: SELF

Type of this instance, automatically specialized in every class

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type BODY: Serializable

popcorn :: Handler :: BODY

Kind of objects returned by deserialize_body
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
private var _body_type: String

popcorn :: Handler :: _body_type

private var _validator: nullable DocumentValidator

popcorn :: Handler :: _validator

Validator used to check body input
fun all(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: all

Handler to all kind of HTTP request methods.
private fun body_type: String

popcorn :: Handler :: body_type

private fun body_type=(body_type: String)

popcorn :: Handler :: body_type=

protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun delete(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: delete

DELETE handler.
fun deserialize_body(req: HttpRequest, res: HttpResponse): nullable BODY

popcorn :: Handler :: deserialize_body

Deserialize the request body
fun get(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: get

GET handler.
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
private fun handle(route: AppRoute, uri: String, req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: handle

Call all(req, res) if route matches uri.
fun hash: Int

core :: Object :: hash

The hash code of the object.
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
private intern fun native_class_name: CString

core :: Object :: native_class_name

The class name of the object in CString format.
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
fun post(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: post

POST handler.
fun put(req: HttpRequest, res: HttpResponse)

popcorn :: Handler :: put

PUT handler.
fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_s: String

core :: Object :: to_s

User readable representation of self.
fun validate_body(req: HttpRequest, res: HttpResponse): nullable String

popcorn :: Handler :: validate_body

Validate body input with validator
fun validator: nullable DocumentValidator

popcorn :: Handler :: validator

Validator used to check body input
protected fun validator=(validator: nullable DocumentValidator)

popcorn :: Handler :: validator=

Validator used to check body input
package_diagram popcorn::Handler Handler core::Object Object popcorn::Handler->core::Object popcorn::Handler... ... popcorn::Handler...->popcorn::Handler

Parents

interface Object

core :: Object

The root of the class hierarchy.

Children

abstract class APIHandler

nitc :: APIHandler

Specific handler for the nitweb API.
class AppHome

popcorn :: AppHome

abstract class AuthHandler

popcorn :: AuthHandler

AuthHandler allows access to session user
class GithubLogin

popcorn :: GithubLogin

Github OAuth login handler.
class GithubLogout

popcorn :: GithubLogout

Destroy user session and redirect to homepage.
class GithubOAuthCallBack

popcorn :: GithubOAuthCallBack

Get the authentification code and translate it to an access token.
class PopLogger

popcorn :: PopLogger

Display log info about request processing.
class RequestClock

popcorn :: RequestClock

Initialize a clock for the resquest.
class Router

popcorn :: Router

Mountable routers
class SessionInit

popcorn :: SessionInit

Initialize session in request if non existent.
class StaticHandler

popcorn :: StaticHandler

Static files server.
abstract class TrackerHandler

popcorn :: TrackerHandler

Base tracker handler

Descendants

class APICatalogContributing

nitc :: APICatalogContributing

Get the list of mpackages contributed by a person
class APICatalogMaintaining

nitc :: APICatalogMaintaining

Get the list of mpackages maintained by a person
class APICatalogPackages

nitc :: APICatalogPackages

Get all the packages from the catalog using pagination
class APICatalogPerson

nitc :: APICatalogPerson

Get a person existing in the catalog
class APICatalogStats

nitc :: APICatalogStats

Get the catalog statistics
class APICatalogTag

nitc :: APICatalogTag

Get the packages related to a tag
class APICatalogTags

nitc :: APICatalogTags

Get all the tags from the catalog
abstract class APICommand

nitc :: APICommand

An API Handler that use a DocCommand to respond
class APIDocdown

nitc :: APIDocdown

Docdown handler accept docdown as POST data and render it as HTML
class APIEntity

nitc :: APIEntity

Return the JSON representation of a MEntity.
class APIEntityAll

nitc :: APIEntityAll

List all definitions accessible from a MEntity.
class APIEntityAncestors

nitc :: APIEntityAncestors

List MEntity ancestors
class APIEntityChildren

nitc :: APIEntityChildren

List MEntity children
class APIEntityCode

nitc :: APIEntityCode

Return the source code of MEntity.
class APIEntityDefs

nitc :: APIEntityDefs

List definitions of a MEntity.
class APIEntityDescendants

nitc :: APIEntityDescendants

List MEntity descendants
class APIEntityDoc

nitc :: APIEntityDoc

Return the full MDoc of a MEntity.
class APIEntityIntros

nitc :: APIEntityIntros

List intro definitions of a MEntity.
class APIEntityLinearization

nitc :: APIEntityLinearization

Linearize super definitions of a MClassDef or a MPropDef if any.
class APIEntityMetadata

nitc :: APIEntityMetadata

Get the package metadata
class APIEntityParents

nitc :: APIEntityParents

List MEntity parents
class APIEntityRedefs

nitc :: APIEntityRedefs

List redef definitions of a MEntity.
class APIEntityUML

nitc :: APIEntityUML

Return the UML diagram for MEntity.
class APIErrorHandler

nitc :: APIErrorHandler

Error handler user to catch non resolved request by the API
abstract class APIFeedBack

nitc :: APIFeedBack

Base handler for feedback features.
class APIInheritanceGraph

nitc :: APIInheritanceGraph

Return the inheritance graph for MEntity.
class APIIniClone

nitc :: APIIniClone

Get the package Git clone command from the ini file
class APIIniContribFile

nitc :: APIIniContribFile

Get the package contrib file
class APIIniContribFileContent

nitc :: APIIniContribFileContent

Get the package contrib file content
class APIIniContributors

nitc :: APIIniContributors

Get the package contributors from the ini file
class APIIniDesc

nitc :: APIIniDesc

Get the package description from the ini file
class APIIniGit

nitc :: APIIniGit

Get the package Git URL from the ini file
class APIIniIssues

nitc :: APIIniIssues

Get the package issues URL from the ini file
class APIIniLicense

nitc :: APIIniLicense

Get the package license from the ini file
class APIIniLicenseFile

nitc :: APIIniLicenseFile

Get the package license file
class APIIniLicenseFileContent

nitc :: APIIniLicenseFileContent

Get the package license file content
class APIIniMaintainer

nitc :: APIIniMaintainer

Get the package maintainer from the ini file
class APILight

nitc :: APILight

Highlight handler accept source code as POST data and render it as HTML with nitpick messages
class APIList

nitc :: APIList

List all mentities.
class APIRandom

nitc :: APIRandom

Return a random list of MEntities.
class APIRouter

nitc :: APIRouter

A Rooter dedicated to APIHandlers.
class APISearch

nitc :: APISearch

Search mentities from a cmd string.
class APIStars

nitc :: APIStars

Stars attributed to mentities
class APIStarsBest

nitc :: APIStarsBest

Best rated entities
class APIStarsDimension

nitc :: APIStarsDimension

Stars attributed to mentities by dimension
class APIStarsMost

nitc :: APIStarsMost

Most rated entities
class APIStarsUsers

nitc :: APIStarsUsers

Best rated entities
class APIStarsWorst

nitc :: APIStarsWorst

Best rated entities
class APIUserStars

nitc :: APIUserStars

Stars attributed to mentities by user
class App

popcorn :: App

Popcorn application.
class GithubUser

popcorn :: GithubUser

Get the currently logged in user from session.
class PopTracker

popcorn :: PopTracker

Saves logs into a MongoDB collection
class PopTrackerAPI

popcorn :: PopTrackerAPI

JSON API of the PopTracker
class PopTrackerBrowsers

popcorn :: PopTrackerBrowsers

Group and count entries by browser
class PopTrackerEntries

popcorn :: PopTrackerEntries

List all tracker log entries
class PopTrackerQueries

popcorn :: PopTrackerQueries

Group and count entries by query string
class PopTrackerResponseTime

popcorn :: PopTrackerResponseTime

Return last month response time

Class definitions

popcorn $ Handler
# 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

popcorn :: pop_json $ Handler
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