examples: annotate examples
[nit.git] / lib / nitcorn / restful.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Support module for the `nitrestful` tool and the `restful` annotation
16 #
17 # The `restful` annotation is applied on a method to assign it to an HTTP resource.
18 # The `restful` method must be a property of a subclass of `RestfulAction` and
19 # return an `HTTPResponse`.
20 # Once an instance of the class is assigned to a route, the method
21 # can be invoked as a resource under that route.
22 # The returned `HTTPResponse` will be sent back to the client.
23 #
24 # The arguments of the method must be deserializable.
25 # So use simple data types like `String`, `Int`, `Float`, etc.
26 # or any other `Serializable` class.
27 # The method is invoked only if all the arguments are correctly passed
28 # in the JSON format by the HTTP client.
29 # There is one exception, `String` arguments are returned as is,
30 # they don't need the surrounding `""`.
31 # If an argument is missing or there a format error, the `answer` method responds to the request.
32 # Arguments that are `nullable` are optional,
33 # if they are missing `null` is passed to the `restful` method.
34 #
35 # The annotation accepts three kinds of arguments, in any order:
36 #
37 # * String literals rename or add an alias for the HTTP resource.
38 # By default, the name of the HTTP resource is the name of the `restful` method.
39 # The first string literal replaces the default name,
40 # while additional string literals add aliases.
41 #
42 # * Ids such as `GET`, `POST`, `PUT` and `DELETE` restrict which HTTP methods
43 # are accepted. By default, all HTTP methods are accepted.
44 #
45 # * The `async` keyword triggers executing calls to this service asynchronously
46 # by the `thread_pool` attribute of the `RestfulAction`.
47 # By default, each call are executed on the same thread in a FIFO order.
48 #
49 # See the example at `lib/nitcorn/examples/restful_annot.nit` or
50 # a real world use case at `contrib/benitlux/src/server/benitlux_controller.nit`.
51 #
52 # The `restful` annotation is implemented by then `nitrestful` tool.
53 # To compile a module (`my_module.nit`) that uses the `restful` annotation:
54 #
55 # * Run `nitrestful my_module.nit` to produce `my_module_rest.nit`
56 # * Link `my_module_rest.nit` at compilation: `nitc my_module.nit -m my_module_rest.nit`.
57 module restful is new_annotation(restful)
58
59 import nitcorn
60 private import json
61 import pthreads::threadpool
62
63 # Action with `restful` methods
64 class RestfulAction
65 super Action
66
67 redef fun answer(request, truncated_uri) do return new HttpResponse(400)
68
69 # Deserialize `val` from JSON for a parameter typed by `static_type`
70 #
71 # Accepts `nullable String` for convenience, but returns `null` when `val == null`.
72 #
73 # This method is called by the code generated by `nitrestful`.
74 # It can be specialized to customize its behavior.
75 protected fun deserialize_arg(val: nullable String, static_type: String): nullable Object
76 do
77 if val == null then return null
78
79 var deserializer = new JsonDeserializer(val)
80 var obj = deserializer.deserialize(static_type)
81
82 if deserializer.errors.not_empty then
83 print_error deserializer.errors.join("\n")
84 return null
85 end
86
87 return obj
88 end
89
90 # Thread pool used by methods annotated with `restful(async)`
91 var thread_pool = new ThreadPool is writable
92 end
93
94 # Thread dedicated to a single `request`
95 abstract class RestfulTask
96 super Task
97
98 # Type of `action`
99 type A: RestfulAction
100
101 # Receiver action
102 var action: A
103
104 # Request that created this thread
105 var request: HttpRequest
106
107 # Server handling the `request`
108 var http_server: HttpServer
109
110 # Indirection to the real method in `action`
111 protected fun indirect_restful_method: HttpResponse is abstract
112
113 redef fun main
114 do
115 var response = indirect_restful_method
116 http_server.respond response
117 http_server.close
118 end
119 end