Learn how to use the WSBLib library with the complete documentation.
Learn how to create a web server using the WSBLib library.
First, the entire request cycle is handled by you. You manipulate the data sent by the client, process the request and send the response, all this using the WSBLib classes, which facilitate this whole cycle. A request cycle using WSBLib looks like this:
If you were to create this from scratch, without using WSBLib, you’d have to do all of this:
We’ve shortened all these steps to just 4, making it easy to develop your framework or web server.
Next, we will show the basic structure of a WSBLib server and explain the function of each of the classes, methods and others. Here’s the code for this simple server:
from wsblib.route import Route
from wsblib.server import Client, Server
from wsblib.request import ProcessRequest
from wsblib.request import RequestData
import http_pyparser
def index():
return 'Hello World!'
index_route = Route(index, '/')
request = ProcessRequest((index_route,))
server = Server()
server.start('127.0.0.1', 2808)
print('Server running in http://127.0.0.1:2808')
while True:
client = server.wait_client()
processed_request = request.process(client)
if processed_request:
request_data = processed_request.request
process_type = processed_request.type
if process_type == 'route':
response = processed_request.route.get_route_response(request_data)
else:
response = processed_request.route.get_callback_response(request_data)
http = http_pyparser.response.make_response(response)
client.send_message(http)
client.destroy()
This example server does not use threads, that is, it can only serve another request after the current request is completed. You can rearrange this code so that threads are used.
In the code snippet below, we create a route on the / path, which will call the index_route function to get a response and return it to the client:
def index():
return 'Hello World!'
index_route = Route(index, '/')
This class is used to manipulate and obtain data from the route requested by the user, being able to check methods, obtain parameters (for dynamic routes) and others. To create an instance of this class, the required arguments are:
FunctionType);str);tuple, optional).If we want, for example, to create a route that creates, reads, updates and deletes data (CRUD), the arguments passed would be like this:
profile_route = Route(profile, '/profile', methods=('GET', 'POST', 'PUT', 'DELETE'))
There is a special condition for the path argument. If you want to create a dynamic route, where you can access the data that was placed in the path, the path contains “variables” between “<” and “>” signs, see an example:
dynamic_route = Route(users, '/user/<username>')
For the users function to be called, the <username> parameter must be filled in, for example: /users/firlast. Otherwise, a 404 (Not Found) error will be returned to the client. You can access the dynamic route parameter later through the request data, getting the value of the parameter through its name, for example:
def users(request):
return request.parameters.get('username')
Route classThere are some methods of the Route class that can be accessed to check and get data. The methods are:
get_parameters: This function receives an argument called requested_path, of type str, if the registered route is dynamic, this method will obtain these parameters from the requested_path argument. If the registered route path does not match the requested path, False is returned. This method does not need to be used directly.match_route: Checks if the path specified by the path argument is the same as the path of the registered route.accept_method: Checks if the method passed by the argument is accepted by the route.get_route_response: Gets the return of the route’s callback function to use as the route’s response. The request argument is only passed as an argument to the callback function, if it requests, so that it can get data from the request. This method turns the function’s response into an instance of the http_pyparser.Response class.There is a class called ProcessRequest that processes the request and returns an object ready, with data from the request and the response of the requested route. To create an instance of this class, it is necessary to pass a tuple (or list) containing all the routes of the application, that is, all instances of the Route class, see:
def index():
return 'Hello World!'
# create a route in "/" path
index_route = Route(index, '/')
# instantiating the class to process requests
request = ProcessRequest((index_route,))
In the example above, we are passing the index route (in the path “/”) as an argument to the ProcessRequest class inside a tuple.
The ProcessRequest class has a single public method, the process method, which processes a client request. This method will be responsible for verifying whether the requested route exists in the application and whether the requested method is accepted by the route.
The Server class is responsible for manipulating the socket of the application, receiving connections from clients and manipulating this data. In the code snippet below, we create an instance of the Server class and use the Server.start method to start the server, passing the host and port to be used:
server = Server()
# listening for client connections
server.start('127.0.0.1', 2808)
With that, the host is ready to receive requests, but still won’t respond to any connection, because the server simply still doesn’t accept connections. To receive requests, the Server.wait_client method is used. This method will wait for a request, after receiving it, an instance of the Client class is returned, storing the client data and the raw HTTP message.
The
Clientclass will very rarely need to be used by you, it will only be used by theProcessRequest.processmethod to process the request.
We finally got to accepting connections and processing requests. See the code below, we will explain each detail below:
while True:
client = server.wait_client()
processed_request = request.process(client)
if processed_request:
request_data = processed_request.request
process_type = processed_request.type
if process_type == 'route':
response = processed_request.route.get_route_response(request_data)
else:
response = processed_request.route.get_callback_response(request_data)
http = http_pyparser.response.make_response(response)
client.send_message(http)
client.destroy()
As you can see, the entire processing part of the request is within a while loop, that is, after a request is processed, the server can already receive a new request from another client.
Server.wait_client method. This method will return an instance of the Client class, which will be processed right after.client = server.wait_client()
ProcessRequest class and the process method, passing the instance of the Client class returned by the server.wait_client method. The process method will return an object called RequestProcessed, which contains data from the request and response to the client.processed_request = request.process(client)
processed_request.request (like cookies, headers, method, path, etc) and then we get the response type (in processed_request.type), to know if it is an error or a response generated by the requested route.if processed_request:
request_data = processed_request.request
process_type = processed_request.type
processed_request.route.get_route_response method, passing the request_data variable as an argument. Otherwise, if the response is an error, we use the processed_request.route.get_callback_response method. Both methods returned a Response object, from the HTTPPyParser library, containing all the response data if process_type == 'route':
response = processed_request.route.get_route_response(request_data)
else:
response = processed_request.route.get_callback_response(request_data)
Response object (also from the library) to the http_pyparser.response.make_response method, which returns a string. http = http_pyparser.response.make_response(response)
http variable using the send_message method of the Client class. After that, we use the destroy() method to close the connection with the client. client.send_message(http)
client.destroy()
After these 06 steps, the request was processed and the response was sent to the client.