nitweb: split APIRouter in modules
[nit.git] / src / web / web_base.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 # Base classes used by `nitweb`.
16 module web_base
17
18 import model::model_views
19 import model::model_json
20 import doc_down
21 import popcorn
22 import popcorn::pop_config
23 import popcorn::pop_repos
24
25 # Nitweb config file.
26 class NitwebConfig
27 super AppConfig
28
29 redef var default_db_name = "nitweb"
30
31 # Model to use.
32 var model: Model
33
34 # MModule used to flatten model.
35 var mainmodule: MModule
36
37 # Modelbuilder used to access sources.
38 var modelbuilder: ModelBuilder
39 end
40
41 # Specific nitcorn Action that uses a Model
42 class ModelHandler
43 super Handler
44
45 # App config.
46 var config: NitwebConfig
47
48 # Find the MEntity ` with `full_name`.
49 fun find_mentity(model: ModelView, full_name: nullable String): nullable MEntity do
50 if full_name == null then return null
51 return model.mentity_by_full_name(full_name.from_percent_encoding)
52 end
53
54 # Init the model view from the `req` uri parameters.
55 fun init_model_view(req: HttpRequest): ModelView do
56 var view = new ModelView(config.model)
57 var show_private = req.bool_arg("private") or else false
58 if not show_private then view.min_visibility = protected_visibility
59
60 view.include_fictive = req.bool_arg("fictive") or else false
61 view.include_empty_doc = req.bool_arg("empty-doc") or else true
62 view.include_test_suite = req.bool_arg("test-suite") or else false
63 view.include_attribute = req.bool_arg("attributes") or else true
64
65 return view
66 end
67 end
68
69 # Specific handler for nitweb API.
70 abstract class APIHandler
71 super ModelHandler
72
73 # The JSON API does not filter anything by default.
74 #
75 # So we can cache the model view.
76 var view: ModelView is lazy do
77 var view = new ModelView(config.model)
78 view.min_visibility = private_visibility
79 view.include_fictive = true
80 view.include_empty_doc = true
81 view.include_attribute = true
82 view.include_test_suite = true
83 return view
84 end
85
86 # Try to load the mentity from uri with `/:id`.
87 #
88 # Send 400 if `:id` is null.
89 # Send 404 if no entity is found.
90 # Return null in both cases.
91 fun mentity_from_uri(req: HttpRequest, res: HttpResponse): nullable MEntity do
92 var id = req.param("id")
93 if id == null then
94 res.error 400
95 return null
96 end
97 var mentity = find_mentity(view, id)
98 if mentity == null then
99 res.error 404
100 end
101 return mentity
102 end
103 end
104
105 # A Rooter dedicated to APIHandlers.
106 class APIRouter
107 super Router
108
109 # App config
110 var config: NitwebConfig
111 end
112
113 redef class MEntity
114
115 # URL to `self` within the web interface.
116 fun web_url: String do return "/doc/" / full_name
117
118 # URL to `self` within the JSON api.
119 fun api_url: String do return "/api/entity/" / full_name
120
121 redef fun json do
122 var obj = super
123 obj["web_url"] = web_url
124 obj["api_url"] = api_url
125 return obj
126 end
127
128 # Get the full json repesentation of `self` with MEntityRefs resolved.
129 fun api_json(handler: ModelHandler): JsonObject do return json
130 end
131
132 redef class MEntityRef
133 redef fun json do
134 var obj = super
135 obj["web_url"] = mentity.web_url
136 obj["api_url"] = mentity.api_url
137 obj["name"] = mentity.name
138 obj["mdoc"] = mentity.mdoc_or_fallback
139 obj["visibility"] = mentity.visibility
140 obj["location"] = mentity.location
141 var modifiers = new JsonArray
142 for modifier in mentity.collect_modifiers do
143 modifiers.add modifier
144 end
145 obj["modifiers"] = modifiers
146 var mentity = self.mentity
147 if mentity isa MMethod then
148 obj["msignature"] = mentity.intro.msignature
149 else if mentity isa MMethodDef then
150 obj["msignature"] = mentity.msignature
151 else if mentity isa MVirtualTypeProp then
152 obj["bound"] = to_mentity_ref(mentity.intro.bound)
153 else if mentity isa MVirtualTypeDef then
154 obj["bound"] = to_mentity_ref(mentity.bound)
155 end
156 return obj
157 end
158 end
159
160 redef class MDoc
161
162 # Add doc down processing
163 redef fun json do
164 var obj = super
165 obj["synopsis"] = synopsis
166 obj["documentation"] = documentation
167 obj["comment"] = comment
168 obj["html_synopsis"] = html_synopsis.write_to_string
169 obj["html_documentation"] = html_documentation.write_to_string
170 obj["html_comment"] = html_comment.write_to_string
171 return obj
172 end
173 end
174
175 redef class MModule
176 redef fun api_json(handler) do
177 var obj = super
178 obj["intro_mclassdefs"] = to_mentity_refs(collect_intro_mclassdefs(private_view))
179 obj["redef_mclassdefs"] = to_mentity_refs(collect_redef_mclassdefs(private_view))
180 obj["imports"] = to_mentity_refs(in_importation.direct_greaters)
181 return obj
182 end
183 end
184
185 redef class MClass
186 redef fun api_json(handler) do
187 var obj = super
188 obj["all_mproperties"] = to_mentity_refs(collect_accessible_mproperties(private_view))
189 obj["intro_mproperties"] = to_mentity_refs(collect_intro_mproperties(private_view))
190 obj["redef_mproperties"] = to_mentity_refs(collect_redef_mproperties(private_view))
191 obj["parents"] = to_mentity_refs(collect_parents(private_view))
192 return obj
193 end
194 end
195
196 redef class MClassDef
197 redef fun json do
198 var obj = super
199 obj["intro"] = to_mentity_ref(mclass.intro)
200 obj["mpackage"] = to_mentity_ref(mmodule.mpackage)
201 return obj
202 end
203
204 redef fun api_json(handler) do
205 var obj = super
206 obj["intro_mpropdefs"] = to_mentity_refs(collect_intro_mpropdefs(private_view))
207 obj["redef_mpropdefs"] = to_mentity_refs(collect_redef_mpropdefs(private_view))
208 return obj
209 end
210 end
211
212 redef class MProperty
213 redef fun json do
214 var obj = super
215 obj["intro_mclass"] = to_mentity_ref(intro_mclassdef.mclass)
216 obj["mpackage"] = to_mentity_ref(intro_mclassdef.mmodule.mpackage)
217 return obj
218 end
219 end
220
221 redef class MPropDef
222 redef fun json do
223 var obj = super
224 obj["intro"] = to_mentity_ref(mproperty.intro)
225 obj["intro_mclassdef"] = to_mentity_ref(mproperty.intro.mclassdef)
226 obj["mmodule"] = to_mentity_ref(mclassdef.mmodule)
227 obj["mgroup"] = to_mentity_ref(mclassdef.mmodule.mgroup)
228 obj["mpackage"] = to_mentity_ref(mclassdef.mmodule.mpackage)
229 return obj
230 end
231 end
232
233 redef class MClassType
234 redef var web_url = mclass.web_url is lazy
235 end
236
237 redef class MNullableType
238 redef var web_url = mtype.web_url is lazy
239 end
240
241 redef class MParameterType
242 redef var web_url = mclass.web_url is lazy
243 end
244
245 redef class MVirtualType
246 redef var web_url = mproperty.web_url is lazy
247 end
248
249 redef class POSetElement[E]
250 super Jsonable
251
252 # Return JSON representation of `self`.
253 fun json: JsonObject do
254 assert self isa POSetElement[MEntity]
255 var obj = new JsonObject
256 obj["greaters"] = to_mentity_refs(greaters)
257 obj["direct_greaters"] = to_mentity_refs(direct_greaters)
258 obj["direct_smallers"] = to_mentity_refs(direct_smallers)
259 obj["smallers"] = to_mentity_refs(smallers)
260 return obj
261 end
262
263 redef fun to_json do return json.to_json
264 end