# This file is part of NIT ( http://www.nitlanguage.org ). # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # 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 private import json import pthreads::threadpool # Action with `restful` methods class RestfulAction super Action redef fun answer(request, truncated_uri) do return new HttpResponse(400) # 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, static_type: String): nullable Object do if val == null then return null var deserializer = new JsonDeserializer(val) var obj = deserializer.deserialize(static_type) if deserializer.errors.not_empty then print_error deserializer.errors.join("\n") return null end 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