examples: annotate examples
[nit.git] / lib / nitcorn / restful.nit
index 158643a..a7580a4 100644 (file)
 # limitations under the License.
 
 # Support module for the `nitrestful` tool and the `restful` annotation
+#
+# The `restful` annotation is applied on a method to assign it to an HTTP resource.
+# The `restful` method must be a property of a subclass of `RestfulAction` and
+# return an `HTTPResponse`.
+# Once an instance of the class is assigned to a route, the method
+# can be invoked as a resource under that route.
+# The returned `HTTPResponse` will be sent back to the client.
+#
+# The arguments of the method must be deserializable.
+# So use simple data types like `String`, `Int`, `Float`, etc.
+# or any other `Serializable` class.
+# The method is invoked only if all the arguments are correctly passed
+# in the JSON format by the HTTP client.
+# There is one exception, `String` arguments are returned as is,
+# they don't need the surrounding `""`.
+# If an argument is missing or there a format error, the `answer` method responds to the request.
+# Arguments that are `nullable` are optional,
+# if they are missing `null` is passed to the `restful` method.
+#
+# The annotation accepts three kinds of arguments, in any order:
+#
+# * String literals rename or add an alias for the HTTP resource.
+#   By default, the name of the HTTP resource is the name of the `restful` method.
+#   The first string literal replaces the default name,
+#   while additional string literals add aliases.
+#
+# * Ids such as `GET`, `POST`, `PUT` and `DELETE` restrict which HTTP methods
+#   are accepted. By default, all HTTP methods are accepted.
+#
+# * The `async` keyword triggers executing calls to this service asynchronously
+#   by the `thread_pool` attribute of the `RestfulAction`.
+#   By default, each call are executed on the same thread in a FIFO order.
+#
+# See the example at `lib/nitcorn/examples/restful_annot.nit` or
+# a real world use case at `contrib/benitlux/src/server/benitlux_controller.nit`.
+#
+# The `restful` annotation is implemented by then `nitrestful` tool.
+# To compile a module (`my_module.nit`) that uses the `restful` annotation:
+#
+# * Run `nitrestful my_module.nit` to produce `my_module_rest.nit`
+# * Link `my_module_rest.nit` at compilation: `nitc my_module.nit -m my_module_rest.nit`.
 module restful is new_annotation(restful)
 
 import nitcorn
-import json::serialization
+private import json
+import pthreads::threadpool
 
 # Action with `restful` methods
 class RestfulAction
@@ -24,18 +66,18 @@ class RestfulAction
 
        redef fun answer(request, truncated_uri) do return new HttpResponse(400)
 
-       # Service to deserialize arguments from JSON
+       # Deserialize `val` from JSON for a parameter typed by `static_type`
        #
        # Accepts `nullable String` for convenience, but returns `null` when `val == null`.
        #
        # This method is called by the code generated by `nitrestful`.
        # It can be specialized to customize its behavior.
-       protected fun deserialize_arg(val: nullable String): nullable Object
+       protected fun deserialize_arg(val: nullable String, static_type: String): nullable Object
        do
                if val == null then return null
 
                var deserializer = new JsonDeserializer(val)
-               var obj = deserializer.deserialize
+               var obj = deserializer.deserialize(static_type)
 
                if deserializer.errors.not_empty then
                        print_error deserializer.errors.join("\n")
@@ -44,4 +86,34 @@ class RestfulAction
 
                return obj
        end
+
+       # Thread pool used by methods annotated with `restful(async)`
+       var thread_pool = new ThreadPool is writable
+end
+
+# Thread dedicated to a single `request`
+abstract class RestfulTask
+       super Task
+
+       # Type of `action`
+       type A: RestfulAction
+
+       # Receiver action
+       var action: A
+
+       # Request that created this thread
+       var request: HttpRequest
+
+       # Server handling the `request`
+       var http_server: HttpServer
+
+       # Indirection to the real method in `action`
+       protected fun indirect_restful_method: HttpResponse is abstract
+
+       redef fun main
+       do
+               var response = indirect_restful_method
+               http_server.respond response
+               http_server.close
+       end
 end