Update doc structure, and fixed a few links.
This commit is contained in:
51
doc/wiki/documentation/Connectors.md
Normal file
51
doc/wiki/documentation/Connectors.md
Normal file
@@ -0,0 +1,51 @@
|
||||
The main goal of the connectors is to let you choose a target at compile time.
|
||||
This allows you to concentrate on your business during development time and then decide which target you choose at deployment time.
|
||||
The current connectors are:
|
||||
* Nino
|
||||
* FastCGI
|
||||
* CGI
|
||||
* OpenShift
|
||||
|
||||
The most widely used workflow is to use Nino on your development machine and FastCGI on your production server.
|
||||
Nino being a web server written entirely in Eiffel, you can inspect your HTTP requests and respones in EiffelStudio which is great during development.
|
||||
On the other hand, FastCGI is great at handling concurrent requests and coupled with Apache (or another web production server), you don't even need to worry about the lifecyle of your application (creation and destruction) as Apache will do it for you!
|
||||
|
||||
Let's now dig into each of the connecters.
|
||||
|
||||
# Nino
|
||||
|
||||
Nino is a web server entirely written in Eiffel.
|
||||
The goal of Nino is to provide a simple web server for development (like Java, Python and Ruby provide).
|
||||
Nino is currently maintained by Javier Velilla and the repository can be found here: https://github.com/jvelilla/EiffelWebNino
|
||||
|
||||
# FastCGI
|
||||
|
||||
FastCGI is a protocol for interfacing an application server with a web server.
|
||||
It is an improvement over CGI as FastCGI supports long running processes, i.e. processes than can handle multipe requests during their lifecyle. CGI, on the other hand, launches a new process for every new request which is quite time consuming.
|
||||
FastCGI is implemented by every major web servers: Apache, IIS, Nginx, ...
|
||||
We recommend to use FastCGI instead of CGI as it is way more faster.
|
||||
You can read more about FastCGI here: http://www.fastcgi.com/
|
||||
|
||||
# CGI
|
||||
|
||||
CGI predates FastCGI and is also a protocol for interfacing an application server with a web server.
|
||||
His main drawback (and the reason why FastCGI was created) is that it launches a new process for every new request, which is quite time consuming.
|
||||
We recommend to use FastCGI instead of CGI as it is way more faster.
|
||||
|
||||
# OpenShift
|
||||
|
||||
OpenShift is a cloud computing platform as a service product from Red Hat.
|
||||
It basically let's you run your application in the cloud.
|
||||
More informations are available here: https://www.openshift.com
|
||||
|
||||
# Writing your own
|
||||
|
||||
It's fairly easy to write your own connector. Just inherit from these classes:
|
||||
* WGI_CONNECTOR
|
||||
* WGI_ERROR_STREAM
|
||||
* WGI_INPUT_STREAM
|
||||
* WGI_OUTPUT_STREAM
|
||||
* WSF_SERVICE_LAUNCHER
|
||||
|
||||
|
||||
See WSF_CONNECTOR
|
||||
27
doc/wiki/documentation/Filter.md
Normal file
27
doc/wiki/documentation/Filter.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Introduction
|
||||
|
||||
The basic idea of a filter is to pre-process incoming data and post-process outgoing data.
|
||||
Filters are part of a filter chain, thus following the [chain of responsability design pattern](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern).
|
||||
|
||||
Each filter decides to call the next filter or not.
|
||||
|
||||
# Levels
|
||||
|
||||
In EWF, there are two levels of filters.
|
||||
|
||||
## WSF_FILTER
|
||||
|
||||
Typical examples of such filters are: logging, compression, routing (WSF_ROUTING_FILTER), ...
|
||||
|
||||
## WSF_FILTER_HANDLER
|
||||
|
||||
Handler that can also play the role of a filter.
|
||||
|
||||
Typical examples of such filters are: authentication, ...
|
||||
|
||||
# References
|
||||
|
||||
Filters (also called middelwares) in other environments:
|
||||
* in Python: http://www.wsgi.org/en/latest/libraries.html
|
||||
* in Node.js: http://expressjs.com/guide.html#middleware
|
||||
* in Apache: http://httpd.apache.org/docs/2.2/en/filter.html
|
||||
21
doc/wiki/documentation/HTTP-client-library.md
Normal file
21
doc/wiki/documentation/HTTP-client-library.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# HTTP Library Features
|
||||
The following list of features are taken form the book [RESTful Web Services](http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260/ref=sr_1_1?ie=UTF8&qid=1322155984&sr=8-1)
|
||||
|
||||
* **HTTPS**: _It must support HTTPS and SSL certificate validation_
|
||||
|
||||
* **HTTP methods**: _It must support at least the five main HTTP methods: GET, HEAD, POST, PUT, and DELETE. Optional methods
|
||||
OPTIONS and TRACE, and WebDAV extensions like MOVE, ._
|
||||
* **Custom data** : _It must allow the programmer to customize the data sent as the entity-body of a
|
||||
PUT or POST request._
|
||||
* **Custom headers** : _It must allow the programmer to customize a request’s HTTP headers_
|
||||
* **Response Codes** : _It must give the programmer access to the response code and headers of an HTTP
|
||||
response; not just access to the entity-body._
|
||||
* **Proxies**: _It must be able to communicate through an HTTP proxy_
|
||||
|
||||
* **Compression**:_it should automatically request data in compressed form to save
|
||||
bandwidth, and transparently decompress the data it receives._
|
||||
* **Caching**:_It should automatically cache the responses to your requests._
|
||||
* **Auth methods** : _It should transparently support the most common forms of HTTP authentication:
|
||||
Basic, Digest, and WSSE._
|
||||
* **Cookies** :_It should be able to parse and create HTTP cookie strings_
|
||||
* **Redirects**:_It should be able to transparently follow HTTP redirects_
|
||||
188
doc/wiki/documentation/Library-conneg.md
Normal file
188
doc/wiki/documentation/Library-conneg.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Server-driven content negotiation
|
||||
|
||||
EWF supports server-driven content content negotiation, as defined in [HTTP/1.1 Content Negotiation](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1) . To enable this facility:
|
||||
|
||||
1. Add ${EWF}/library/network/protocol/conneg/conneg.ecf to your system ECF.
|
||||
1. In the class where your handlers reside, add an attribute `conneg: CONNEG_SERVER_SIDE`, and ensure it is always attached (create in the creation procedure, or make it a once, or add an attribute body). An example creation call is: `create conneg.make ({HTTP_MIME_TYPES}.application_json, "en", "UTF-8", "")`.
|
||||
|
||||
That call defines our defaults for media-type, language, charset and encoding, respectively. The encoding could also be written as `"identity"`. It means no compression. As an alternative, we might code `"gzip"`.
|
||||
|
||||
The user agent (a web browser, for example. or the curl program), can request different representations by using headers. For example, `Accept: application/json; q=0.2, application/xml` says the client would be very happy to get back an XML representation (if you omit the q for quality parameter, it defaults to 1, which is best), but (s)he will tolerate JSON. Clearly, we are going to be able to satisfy that client, as we serve JSON by default. But what if the client had requested `Accept: application/xml;q=0.8, text/html`? In this example, we are going to serve both JSON and XML representations upon request. A client who requests `Accept: text/html, text/plain` is going to be disappointed. For the other aspects (language, charset and encoding), we are not going to offer any choices. That does not mean we ignore the client's headers for these aspects. We are going to check if our representation is acceptable to the client, and if not, return a 406 Not Acceptable response (an alternative is to send our representation anyway, and let the user decide whether or not to use it).
|
||||
|
||||
Next, we need to declare all the representations we support:
|
||||
|
||||
mime_types_supported: LINKED_LIST [STRING] is
|
||||
-- Media types `Current' supports
|
||||
once
|
||||
create Result.make
|
||||
Result.put_front ({HTTP_MIME_TYPES}.application_xml)
|
||||
Result.put_front ({HTTP_MIME_TYPES}.application_json)
|
||||
ensure
|
||||
mime_types_supported_not_void: Result /= Void
|
||||
no_void_entry: not Result.has (Void)
|
||||
end
|
||||
|
||||
charsets_supported: LINKED_LIST [STRING] is
|
||||
-- Character sets `Current' supports
|
||||
once
|
||||
create Result.make
|
||||
Result.put_front ("UTF-8")
|
||||
ensure
|
||||
charsets_supported_not_void: Result /= Void
|
||||
no_void_entry: not Result.has (Void)
|
||||
end
|
||||
|
||||
encodings_supported: LINKED_LIST [STRING] is
|
||||
-- Encodings `Current' supports
|
||||
once
|
||||
create Result.make
|
||||
Result.put_front ("identity")
|
||||
Result.put_front ("") -- identity encoding
|
||||
ensure
|
||||
encoding_supported_not_void: Result /= Void
|
||||
no_void_entry: not Result.has (Void)
|
||||
end
|
||||
|
||||
languages_supported: LINKED_LIST [STRING] is
|
||||
-- Languages `Current' supports
|
||||
once
|
||||
create Result.make
|
||||
Result.put_front ("en")
|
||||
ensure
|
||||
languages_supported_not_void: Result /= Void
|
||||
no_void_entry: not Result.has (Void)
|
||||
end
|
||||
|
||||
Now we are in a position to do some negotiating. At the beginning of your handler(s), code:
|
||||
|
||||
|
||||
local
|
||||
l_media_variants: MEDIA_TYPE_VARIANT_RESULTS
|
||||
l_is_head: BOOLEAN
|
||||
h: HTTP_HEADER
|
||||
l_msg: STRING
|
||||
do
|
||||
l_is_head := False -- or `True' if this is for a HEAD handler
|
||||
l_media_variants:= conneg.media_type_preference (mime_types_supported, a_req.http_accept)
|
||||
if not l_media_variants.is_acceptable then
|
||||
send_unacceptable_media_type (a_res, l_is_head)
|
||||
elseif not conneg.charset_preference (charsets_supported, a_req.http_accept_charset).is_acceptable then
|
||||
send_unacceptable_charset (a_res, l_is_head)
|
||||
elseif not conneg.encoding_preference (encodings_supported, a_req.http_accept_encoding).is_acceptable then
|
||||
send_unacceptable_encoding (a_res, l_is_head)
|
||||
elseif not conneg.language_preference (languages_supported, a_req.http_accept_language).is_acceptable then
|
||||
send_unacceptable_encoding (a_res)
|
||||
else
|
||||
-- We have agreed a representation, let's go and serve it to the client
|
||||
`
|
||||
|
||||
Now for those `send_unnacceptable_...` routines. They are fairly simple:
|
||||
|
||||
send_unacceptable_media_type (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is
|
||||
-- Send error result as text/plain that the media type is unnacceptable.
|
||||
require
|
||||
a_res_not_void: a_res /= Void
|
||||
status_not_set: not a_res.status_is_set
|
||||
header_not_committed: not a_res.header_committed
|
||||
local
|
||||
l_error_text: STRING
|
||||
do
|
||||
l_error_text := "The requested media type(s) is/are not supported by this server."
|
||||
send_unacceptable (a_res, a_is_head, l_error_text)
|
||||
end
|
||||
|
||||
send_unacceptable_charset (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is
|
||||
-- Send error result as text/plain that the character set is unnacceptable.
|
||||
require
|
||||
a_res_not_void: a_res /= Void
|
||||
status_not_set: not a_res.status_is_set
|
||||
header_not_committed: not a_res.header_committed
|
||||
local
|
||||
l_error_text: STRING
|
||||
do
|
||||
l_error_text := "The requested character set(s) is/are not supported by this server. Only UTF-8 is supported."
|
||||
send_unacceptable (a_res, a_is_head, l_error_text)
|
||||
end
|
||||
|
||||
send_unacceptable_encoding (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is
|
||||
-- Send error result as text/plain that the encoding is unnacceptable.
|
||||
require
|
||||
a_res_not_void: a_res /= Void
|
||||
status_not_set: not a_res.status_is_set
|
||||
header_not_committed: not a_res.header_committed
|
||||
local
|
||||
l_error_text: STRING
|
||||
do
|
||||
l_error_text := "The requested encoding(s) is/are not supported by this server. Only identity is supported."
|
||||
send_unacceptable (a_res, a_is_head, l_error_text)
|
||||
end
|
||||
|
||||
send_unacceptable_language (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is
|
||||
-- Send error result as text/plain that the language unnacceptable.
|
||||
require
|
||||
a_res_not_void: a_res /= Void
|
||||
status_not_set: not a_res.status_is_set
|
||||
header_not_committed: not a_res.header_committed
|
||||
local
|
||||
l_error_text: STRING
|
||||
do
|
||||
l_error_text := "The requested language(s) is/are not supported by this server. Only en (English) is supported."
|
||||
send_unacceptable (a_res, a_is_head, l_error_text)
|
||||
end
|
||||
|
||||
send_unacceptable (a_res: WSF_RESPONSE; a_is_head: BOOLEAN; a_error_text: STRING) is
|
||||
-- Send a_error_text as text/plain that a header is unnacceptable.
|
||||
require
|
||||
a_res_not_void: a_res /= Void
|
||||
status_not_set: not a_res.status_is_set
|
||||
header_not_committed: not a_res.header_committed
|
||||
a_error_text_not_void: a_error_text /= Void
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
do
|
||||
create h.make
|
||||
set_content_type (h, Void)
|
||||
h.put_content_length (a_error_text.count)
|
||||
h.put_current_date
|
||||
a_res.set_status_code ({HTTP_STATUS_CODE}.not_acceptable)
|
||||
a_res.put_header_text (h.string)
|
||||
if not a_is_head then
|
||||
a_res.put_string (a_error_text)
|
||||
end
|
||||
end
|
||||
|
||||
We'll see that `set_content_type` routine in a bit. But for now, we just have to generate the response. Let's go back to that `else ...` bit:
|
||||
|
||||
else
|
||||
-- We have agreed a representation, let's go and serve it to the client
|
||||
create h.make
|
||||
set_content_type (h, a_media_variants)
|
||||
if a_media_variants.media_type ~ {HTTP_MIME_TYPES}.application_xml then
|
||||
l_msg := "<?xml version='1.0' encoding='UTF-8' ?><my-tag>etc."
|
||||
else
|
||||
l_msg := json.value (<some-value>).representation
|
||||
end
|
||||
h.put_content_length (l_msg.count)
|
||||
h.put_current_date
|
||||
a_res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
a_res.put_header_text (h.string)
|
||||
if not a_is_head then
|
||||
a_res.put_string (l_msg)
|
||||
end
|
||||
|
||||
There's that `set_content_type` again. Finally, we will take a look at it:
|
||||
|
||||
set_content_type (a_h: HTTP_HEADER; a_media_variants: MEDIA_TYPE_VARIANT_RESULTS) is
|
||||
-- Set the content=type header in `a_h' according to `a_media_variants'.
|
||||
require
|
||||
a_h_not_void: a_h /= Void
|
||||
do
|
||||
if a_media_variants = Void or else not a_media_variants.is_acceptable then
|
||||
a_h.put_content_type ({HTTP_MIME_TYPES}.text_plain)
|
||||
else
|
||||
a_h.put_content_type (a_media_variants.media_type)
|
||||
end
|
||||
a_h.put_header_key_value ({HTTP_HEADER_NAMES}.header_vary, {HTTP_HEADER_NAMES}.header_accept)
|
||||
end
|
||||
|
||||
Firstly, if we haven't agreed a media-type, then we send our (negative) response as `plain/text`. Otherwise we will send the response in the agreed media-type. But in each case we add a `Vary:Accept` header. This tells proxy caches that they have to check the media-type before returning a cached result, as there may be a different representation available. Since we do not vary our representation by language, charset or encoding, we don't add `Vary:Accept-Language,Accept-Charset,Accept-Encoding`. But if we were to negotiate different representations on those dimensions also, we would need to list the appropriate headers in the `Vary` header.
|
||||
9
doc/wiki/documentation/Request-and-response.md
Normal file
9
doc/wiki/documentation/Request-and-response.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Request
|
||||
The class _WSF_REQUEST_ can be used to access data related to the HTTP request.
|
||||
|
||||
**TODO**: describe the request interface
|
||||
|
||||
# Response
|
||||
The class _WSF_RESPONSE_ is the media to send data back to the client.
|
||||
|
||||
**TODO**: describe the response interface
|
||||
17
doc/wiki/documentation/Request.md
Normal file
17
doc/wiki/documentation/Request.md
Normal file
@@ -0,0 +1,17 @@
|
||||
See WSF_REQUEST
|
||||
|
||||
## About parameters
|
||||
Note that by default there is a smart computation for the query/post/... parameters:
|
||||
for instance
|
||||
- `q=a&q=b` : will create a **WSF_MULTIPLE_STRING** parameter with name **q** and value `[a,b]`
|
||||
- `tab[a]=ewf&tab[b]=demo` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "a": "ewf", "b": "demo"}`
|
||||
- `tab[]=ewf&tab[]=demo` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "1": "ewf", "2": "demo"}`
|
||||
- `tab[foo]=foo&tab[foo]=bar` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "foo": "bar"}` **WARNING: only the last `tab[foo]` is kept**.
|
||||
|
||||
Those rules are applied to query, post, path, .... parameters.
|
||||
|
||||
## How to get the input data (i.e entity-body) ?
|
||||
See `{WSF_REQUEST}.read_input_data_into (buf: STRING)`
|
||||
|
||||
## How to get the raw header data (i.e the http header text) ?
|
||||
See `{WSF_REQUEST}.raw_header_data: detachable READABLE_STRING_32`
|
||||
1
doc/wiki/documentation/Response.md
Normal file
1
doc/wiki/documentation/Response.md
Normal file
@@ -0,0 +1 @@
|
||||
See WSF_RESPONSE
|
||||
6
doc/wiki/documentation/Router.md
Normal file
6
doc/wiki/documentation/Router.md
Normal file
@@ -0,0 +1,6 @@
|
||||
The primary goal of the router (class _WSF_ROUTER_) is to dispatch requests according to the request URI.
|
||||
|
||||
See WSF_ROUTER
|
||||
|
||||
**TODO**: describe the router interface
|
||||
|
||||
2
doc/wiki/documentation/Service.md
Normal file
2
doc/wiki/documentation/Service.md
Normal file
@@ -0,0 +1,2 @@
|
||||
EWF Services
|
||||
> See WSF\_SERVICE
|
||||
210
doc/wiki/documentation/index.md
Normal file
210
doc/wiki/documentation/index.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# Current Status
|
||||
* Official repository: <https://github.com/EiffelWebFramework/EWF>
|
||||
* Official website: <http://eiffelwebframework.github.io/EWF/getting-started/>
|
||||
|
||||
# What is EWF?
|
||||
|
||||
Eiffel Web Framework, is mainly a collection of Eiffel libraries designed to be integrated with each other. One benefit is that it supports all core HTTP features, so enable you embrace HTTP as an application protocol to develop web applications. So you do not need to adapt your applications to the web, instead you use the web power. It means you can build different kind of web applications, from Web APIs following the Hypermedia API style (REST style), CRUD web services or just conventional web applications building a session on top of an stateless protocol.
|
||||
|
||||
# EWF core/kernel
|
||||
> The Web Server Foundation (WSF\_) is the core of the framework. It is compliant with the EWSGI interface (WGI\_).
|
||||
|
||||
To build a web [service](#service), the framework provides a set of core components to launch the service, for each [request](#request-and-response), access the data, and send the [response](#request-and-response).
|
||||
The framework also provides a router component to help dispatching the incoming request.
|
||||
|
||||
A service can be a web api, a web interface, … what ever run on top of HTTP.
|
||||
|
||||
<a name="wiki-service"></a>
|
||||
<a name="service"></a>
|
||||
# Service
|
||||
> see interface: **WSF_SERVICE**
|
||||
|
||||
Each incoming http request is processed by the following routine.
|
||||
|
||||
> `{WSF_SERVICE}.execute (req: WSF_REQUEST; res: WSF_RESPONSE)`
|
||||
|
||||
This is the low level of the framework, at this point, `req` provides access to the query and form parameters, input data, headers, ... as specified by the Common Gateway Interface (CGI).
|
||||
The response `res` is the interface to send data back to the client.
|
||||
For convenience, the framework provides richer service interface that handles the most common needs (filter, router, ...).
|
||||
|
||||
> [Learn more about service](Service.md)
|
||||
|
||||
<a name="wiki-request"></a><a name="wiki-response"></a><a name="wiki-request-and-response"></a>
|
||||
<a name="request"></a><a name="response"></a><a name="request-and-response"></a>
|
||||
# Request and Response
|
||||
> see interface: **WSF_REQUEST** and **WSF_RESPONSE**
|
||||
|
||||
Any incoming http request is represented by an new object of type **WSF_REQUEST**.
|
||||
|
||||
**WSF_REQUEST** provides access to
|
||||
+ __meta variables__: CGI variables (coming from the request http header)
|
||||
+ __query parameters__: from the uri ex: `?q=abc&type=pdf`
|
||||
+ __input data__: the message of the request, if this is a web form, this is parsed to build the form parameters. It can be retrieved once.
|
||||
+ __form parameters__: standard parameters from the request input data.
|
||||
- typically available when a web form is sent using POST as content of type `multipart/form-data` or `application/x-www-form-urlencoded`
|
||||
- (advanced usage: it is possible to write mime handler that can processed other type of content, even custom format.)
|
||||
+ __uploaded files__: if files are uploaded, their value will be available from the form parameters, and from the uploaded files as well.
|
||||
+ __cookies variable__: cookies extracted from the http header.
|
||||
+ __path parameters__: note this is related to the router and carry the semantic of the mapping (see the section on router )
|
||||
+ __execution variables__: used by the application to keep value associated with the request.
|
||||
|
||||
The **WSF_RESPONSE** represents the communication toward the client, a service need to provide correct headers, and content. For instance the `Content-Type`, and `Content-Length`. It also allows to send data with chunked encoding.
|
||||
|
||||
> [Learn more about request](Request.md) and [about response](Response.md)
|
||||
|
||||
<a name="wiki-connector"></a>
|
||||
<a name="connector"></a>
|
||||
# Connectors:
|
||||
> see **WGI_CONNECTOR**
|
||||
|
||||
Using EWF, your service is built on top of underlying httpd solution/connectors.
|
||||
Currently 3 main connectors are available:
|
||||
* __CGI__: following the CGI interface, this is an easy solution to run the service on any platform.
|
||||
* __libFCGI__: based on the libfcgi solution, this can be used with Apache, IIS, nginx, ...
|
||||
* __nino__: a standalone server: Eiffel Web Nino allow you to embed a web server anywhere, on any platform without any dependencies on other httpd server.
|
||||
|
||||
At compilation time, you can use a default connector (by using the associated default lib), but you can also use a mixed of them and choose which one to execute at runtime.
|
||||
It is fairly easy to add new connector, it just has to follow the EWSGI interface
|
||||
|
||||
> [Learn more about connector](Connector.md)
|
||||
|
||||
<a name="wiki-router"></a>
|
||||
<a name="router"></a>
|
||||
# Router or Request Dispatcher:
|
||||
> Routes HTTP requests to the proper execution code
|
||||
|
||||
A web application needs to have a clean and elegant URL scheme, and EWF provides a router component to design URLs.
|
||||
|
||||
The association between a URL pattern and the code handling the URL request is called a Router mapping in EWF.
|
||||
|
||||
EWF provides 3 main kinds of mappings
|
||||
+ __URI__: any URL with path being the specified uri.
|
||||
- example: “/users/” redirects any “/users/” and “/users/?query=...”
|
||||
+ __URI-template__: any URL matching the specified URI-template
|
||||
- example: “/project/{name}/” redirects any “/project/foo” or “/project/bar”
|
||||
+ __Starts-with__: any URL starting with the specified path
|
||||
|
||||
Note: in the future, a Regular-Expression based kind will be added in the future, and it is possible to use custom mapping on top of EWF.
|
||||
|
||||
Code:
|
||||
|
||||
router.map ( create {WSF_URI_TEMPLATE_MAPPING}.make (
|
||||
“/project/{name}”, project_handler)
|
||||
)
|
||||
-- And precising the request methods
|
||||
router.map_with_request_methods ( ... , router.methods_GET_POST)
|
||||
|
||||
In the previous code, the `project_handler` is an object conforming to **WSF_HANDLER**, that will process the incoming requests matching URI-template “/project/{name}”.
|
||||
|
||||
Usually, the service will inherit from WSF_ROUTED_SERVICE, which has a `router` attribute.
|
||||
Configuring the URL scheme is done by implementing `{WSF_ROUTED_SERVICE}.setup_router`.
|
||||
|
||||
To make life easier, by inheriting from WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE, a few help methods are available to `map` URI template with agent, and so on.
|
||||
See
|
||||
+ `map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER)`
|
||||
+ `map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]])`
|
||||
+ and same with request methods ...
|
||||
|
||||
...
|
||||
|
||||
Check WSF_\*_HELPER_FOR_ROUTED_SERVICE for other available helper classes.
|
||||
|
||||
How we do that in EWF? : Router with (or without context).
|
||||
Related code: wsf_router, wsf_router_context
|
||||
Examples
|
||||
|
||||
> [Learn more about router](Router.md)
|
||||
|
||||
# EWF components
|
||||
## URI Handler:
|
||||
> Parses the details of the URI (scheme, path, query info, etc.) and exposes them for use.
|
||||
|
||||
How we do that in EWF?: URI Templates, but we could also use regex.
|
||||
Related code: uri_template
|
||||
Examples:
|
||||
|
||||
|
||||
## Mime Parser/ Content Negotiation:
|
||||
> Handles the details of determining the media type, language, encoding, compression (conneg).
|
||||
|
||||
How do we do that in EWF? Content_Negotiation library.
|
||||
Example
|
||||
|
||||
|
||||
## Request Handler
|
||||
> target of request dispatcher + uri handler.
|
||||
|
||||
Here is where we handle GET, POST PUT, etc.
|
||||
|
||||
## Representation Mapping
|
||||
> Converts stored data into the proper representation for responses and handles incoming representations from requests.
|
||||
|
||||
We don’t have a representation library, the developer need to do that.
|
||||
If we want to provide different kind of representations: JSON, XML, HTML, the responsibility is let
|
||||
to the developer to map their domain to the target representation.
|
||||
|
||||
## Http Client:
|
||||
> A simple library to make requests and handle responses from other http servers.
|
||||
|
||||
How we do that in EWF? http client library
|
||||
examples:
|
||||
|
||||
## Authentication/Security:
|
||||
> Handle different auth models. (Basic, Digest?, OAuth, OpenId)
|
||||
|
||||
How we do that in EWF? http_authorization, OpenId, and Cypress
|
||||
examples.
|
||||
|
||||
## Caching:
|
||||
> Support for Caching and conditional request
|
||||
|
||||
How we do that in Eiffel? Policy framework on top of EWF. {{{need_review}}}
|
||||
examples
|
||||
|
||||
|
||||
## EWF HTML5 Widgets
|
||||
|
||||
## EWF policy Framework
|
||||
|
||||
## EWF application generators
|
||||
|
||||
|
||||
<a name="wiki-EWSGI"></a>
|
||||
<a name="EWSGI"></a>
|
||||
# EWSGI Specification
|
||||
|
||||
<a name="wiki-libraries"></a>
|
||||
<a name="libraries"></a>
|
||||
# Libraries
|
||||
|
||||
External libraries are included, such as Cypress OAuth (Security), HTML parsing library, Template Engine Smarty.
|
||||
|
||||
## server
|
||||
* __ewsgi__: Eiffel Web Server Gateway Interface [read more](../EWSGI/index.md).
|
||||
* connectors: various web server connectors for EWSGI
|
||||
* __libfcgi__: Wrapper for libfcgi SDK
|
||||
* __wsf__: Web Server Framework
|
||||
* __router__: URL dispatching/routing based on uri, uri_template, or custom [read more](Router.md).
|
||||
* __filter__: Filter chain [read more](Filter.md).
|
||||
* __wsf_html__: (html and css) Content generator from the server side.
|
||||
* CMS example: <https://github.com/EiffelWebFramework/cms/tree/master/example>
|
||||
|
||||
## protocol
|
||||
* __http__: HTTP related classes, constants for status code, content types, ...
|
||||
* __uri_template__: URI Template library (parsing and expander)
|
||||
* __content_negotiation__: [CONNEG](Library-conneg.md) library (Content-type Negociation)
|
||||
|
||||
## Client
|
||||
* __http_client__: simple [HTTP client](HTTP-client.library.md) based on cURL
|
||||
* __Firebase API__: <https://github.com/EiffelWebFramework/Redwood>
|
||||
|
||||
## Text
|
||||
* __encoder__: Various simple encoders: base64, url-encoder, xml entities, html entities
|
||||
|
||||
## Utils
|
||||
* __error__: very simple/basic library to handle error
|
||||
|
||||
## Security
|
||||
* __http_authentication__ (under EWF/library/server/authentication)
|
||||
* __open_id__ (under EWF/library/security)
|
||||
* __OAuth__ see <https://github.com/EiffelWebFramework/cypress>
|
||||
Reference in New Issue
Block a user