64a06e1e44fee67a62654ba66f843c0a283e6e49
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2017 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Introduce useful services for JSON REST API handlers.
19 # Validation and Deserialization of request bodies:
25 # # Validator used do validate the body
26 # redef var validator = new MyFormValidator
28 # # Define the kind of objects expected by the deserialization process
29 # redef type BODY: MyForm
31 # redef fun post(req, res) do
32 # var post = validate_body(req, res)
33 # if post == null then return # Validation error: let popcorn return a HTTP 400
34 # var form = deserialize_body(req, res)
35 # if form == null then return # Deserialization error: let popcorn return a HTTP 400
37 # # TODO do something with the input
48 # class MyFormValidator
49 # super ObjectValidator
52 # add new StringField("name", min_size=1, max_size=255)
64 # Validator used to check body input
66 # Here we use the `pop_validation` module to validate JSON document from the request body.
67 var validator
: nullable DocumentValidator = null
69 # Validate body input with `validator`
71 # Try to validate the request body as a json document using `validator`:
72 # * Returns the validated string input if the result of the validation is ok.
73 # * Answers a json error and returns `null` if something went wrong.
74 # * If no `validator` is set, returns the body without validation.
79 # class ValidatedHandler
82 # redef var validator = new MyObjectValidator
84 # redef fun post(req, res) do
85 # var body = validate_body(req, res)
86 # if body == null then return # Validation error
87 # # At this point popcorn returned a HTTP 400 code with the validation error
88 # # if the validation failed.
90 # # TODO do something with the input
95 # class MyObjectValidator
96 # super ObjectValidator
99 # add new StringField("name", min_size=1, max_size=255)
103 fun validate_body
(req
: HttpRequest, res
: HttpResponse): nullable String do
106 var validator
= self.validator
107 if validator
== null then return body
109 if not validator
.validate
(body
) then
110 res
.json
(validator
.validation
, 400)
116 # Deserialize the request body
118 # Returns the deserialized request body body or `null` if something went wrong.
119 # If the object cannot be deserialized, answers with a HTTP 400.
121 # See `BODY` and `new_body_object`.
125 # class MyDeserializedHandler
128 # redef type BODY: MyObject
130 # redef fun post(req, res) do
131 # var form = deserialize_body(req, res)
132 # if form == null then return # Deserialization error
133 # # At this point popcorn returned a HTTP 400 code if something was wrong with
134 # # the deserialization process
136 # # TODO do something with the input
147 fun deserialize_body
(req
: HttpRequest, res
: HttpResponse): nullable BODY do
149 var deserializer
= new JsonDeserializer(body
)
150 var form
= deserializer
.deserialize
(body
)
151 if not form
isa BODY or deserializer
.errors
.not_empty
then
152 res
.json_error
("Bad input", 400)
158 # Kind of objects returned by `deserialize_body`
160 # Define it in each sub handlers depending on the kind of objects sent in request bodies.
161 type BODY: Serializable
164 redef class HttpResponse
166 # Write data as JSON and set the right content type header.
167 fun json
(json
: nullable Serializable, status
: nullable Int) do
168 header
["Content-Type"] = media_types
["json"].as(not null)
172 send
(json
.to_json
, status
)
176 # Write error as JSON.
178 # Format: `{"message": message, "status": status}`
179 fun json_error
(message
: String, status
: Int) do
180 var obj
= new JsonObject
181 obj
["status"] = status
182 obj
["message"] = message