/examples/rest_server/src/rest_server.e

http://github.com/jocelyn/EiffelWebReloaded · Specman e · 204 lines · 144 code · 34 blank · 26 comment · 1 complexity · cd2adc9ab3d2fd687ec9e06a580a8755 MD5 · raw file

  1. note
  2. description: "[
  3. A simple example to demonstrate how to build a RESTful server
  4. ]"
  5. date: "$Date$"
  6. revision: "$Revision$"
  7. class
  8. REST_SERVER
  9. inherit
  10. REST_APPLICATION --| Use the provided RESTful implementation
  11. redefine
  12. new_request_context,
  13. execute,
  14. exit_with_code
  15. end
  16. --| Precise which httpd support you want to use, here we use EiffelWebNino
  17. --| you could also use FCGI or CGI
  18. HTTPD_NINO_APPLICATION
  19. redefine
  20. initialize_server,
  21. new_request_context,
  22. execute
  23. end
  24. --| Simple facility to trace your execution
  25. SHARED_LOGGER
  26. create
  27. make
  28. feature {NONE} -- Initialization
  29. make
  30. -- Initialize `Current'.
  31. do
  32. initialize
  33. initialize_handlers
  34. initialize_logger
  35. launch
  36. logger.close
  37. end
  38. initialize_logger
  39. do
  40. logger_cell.replace (create {FILE_LOGGER}.make_with_filename ("server.log"))
  41. end
  42. initialize_server
  43. do
  44. Precursor
  45. base := "/service" --| See `base' for details
  46. --| Let's use 8080 for the port number
  47. --| You can change it
  48. server.configuration.http_server_port := 8080
  49. --| If your application is not design to be run in multithread
  50. --| you can choose to force single_thread request handling
  51. server.configuration.force_single_threaded := True
  52. end
  53. base: detachable STRING
  54. -- Base url used to tell EiffelWebNino what is the "root" for the application
  55. --| basically if your service is http://domain.tld/service
  56. --| and your request such http://domain.tld/service/test?foo=bar
  57. --| the base_url is /service
  58. --| and then, your PATH_INFO will be /test and the QUERY_STRING will be foo=bar
  59. feature {NONE} -- Environment
  60. new_request_context (a_vars: HASH_TABLE [STRING, STRING]; a_input: HTTPD_SERVER_INPUT; a_output: HTTPD_SERVER_OUTPUT): REST_REQUEST_CONTEXT
  61. do
  62. --| Precise our own authentication system
  63. create Result.make_with_authentication (a_vars, a_input, a_output, create {REST_SERVER_AUTHENTICATION})
  64. --| At this point, you can decided to add your own environment variable
  65. --| this is a convenient way to share a value
  66. Result.environment_variables.add_variable (request_count.out, "REQUEST_COUNT")
  67. --| Note that you can also create your own REST_REQUEST_CONTEXT with specific features
  68. end
  69. feature {NONE} -- Handlers
  70. handler_manager: REST_REQUEST_HANDLER_MANAGER
  71. -- This is the main handler manager
  72. -- you can use your own implementation
  73. initialize_handlers
  74. local
  75. h: REST_REQUEST_HANDLER
  76. m: like handler_manager
  77. do
  78. create handler_manager.make (10)
  79. m := handler_manager
  80. --| This /doc is to show a quick documentation of your services,
  81. --| based on the declaration in the various APP_... classes
  82. m.register (create {APP_API_DOCUMENTATION}.make ("/doc", m))
  83. --| An example to handle login/password
  84. m.register (create {APP_ACCOUNT_VERIFY_CREDENTIAL}.make ("/account/verify_credentials"))
  85. --| Various tests ..
  86. m.register (create {APP_TEST}.make ("/test"))
  87. m.register (create {APP_DEBUG_LOG}.make ("/log"))
  88. --| One app to tell the server to exit
  89. create {REST_REQUEST_AGENT_HANDLER} h.make (agent execute_exit_application, "/exit")
  90. h.set_description ("tell the REST server to exit (in FCGI context, this could be used to reload the FCGI server)")
  91. h.enable_request_method_get
  92. h.enable_format_text
  93. m.register (h)
  94. end
  95. feature -- Execution
  96. execute (ctx: like new_request_context)
  97. do
  98. logger.logf (1, "[$3] execute: path_info=$1 (request_count=$2)", <<ctx.path_info, request_count, ctx.environment_variables.remote_addr>>)
  99. Precursor (ctx)
  100. end
  101. execute_default (ctx: like new_request_context)
  102. -- Execute the default behavior
  103. local
  104. rqst_uri: detachable STRING
  105. l_path_info: detachable STRING
  106. h: HTTPD_HEADER
  107. s: STRING
  108. do
  109. create h.make
  110. h.put_refresh (ctx.script_url ("/doc"), 2, {HTTP_STATUS_CODE}.temp_redirect)
  111. h.put_content_type_text_html
  112. create s.make_empty
  113. s := "Request [" + ctx.path_info + "] is not available. <br/>%N";
  114. s.append ("You are being redirected to <a href=%"" + ctx.script_url ("/doc") + "%">/doc</a> in 2 seconds ...%N")
  115. h.put_content_length (s.count)
  116. ctx.output.put_string (h.string)
  117. ctx.output.put_string (s)
  118. end
  119. execute_rescue (ctx: like new_request_context)
  120. -- Execute the default rescue behavior
  121. do
  122. execute_exception_trace (ctx)
  123. end
  124. feature -- Implementation
  125. execute_exception_trace (ctx: like new_request_context)
  126. local
  127. h: HTTPD_HEADER
  128. s: STRING
  129. do
  130. create h.make
  131. h.put_content_type_text_plain
  132. ctx.output.put_string (h.string)
  133. ctx.output.put_string ("Error occurred .. rq="+ request_count.out +"%N")
  134. if attached (create {EXCEPTIONS}).exception_trace as l_trace then
  135. ctx.output.put_string ("<pre>" + l_trace + "</pre>")
  136. end
  137. h.recycle
  138. exit_with_code (-1)
  139. end
  140. execute_exit_application (ctx: REST_REQUEST_CONTEXT; a_format_name: detachable STRING; a_args: detachable STRING)
  141. local
  142. rep: REST_RESPONSE
  143. s: STRING
  144. do
  145. create rep.make ("exit")
  146. rep.headers.put_content_type_text_html
  147. create s.make_empty
  148. s.append_string ("Exited")
  149. s.append_string (" <a href=%"" + ctx.script_url ("/") + "%">start again</a>%N")
  150. rep.set_message (s)
  151. ctx.output.put_string (rep.string)
  152. rep.recycle
  153. exit_with_code (0)
  154. end
  155. exit_with_code (a_code: INTEGER)
  156. do
  157. server.shutdown_server
  158. logger.close;
  159. end
  160. note
  161. copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
  162. license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
  163. source: "[
  164. Eiffel Software
  165. 5949 Hollister Ave., Goleta, CA 93117 USA
  166. Telephone 805-685-1006, Fax 805-685-6869
  167. Website http://www.eiffel.com
  168. Customer support http://support.eiffel.com
  169. ]"
  170. end