Python 1.4 - Analysis Results - Web Service calls and operations support

This documentation is not maintained. Please refer to doc.castsoftware.com/technologies to find the latest updates.

Web Service calls and operations support

See Python 1.4#Frameworksupport for the frameworks and libraries supported.

Once the Python extension analysis is finished, the analyzer will log the final number of web service call and operation objects created for each framework.

Generic service operations

Python Web Service GET/POST/PUT/DELETE operation objects will be used as generic objects for new supported frameworks implementing APIs to access web services on server side.

For now, FastAPI and CherryPy have been developed with the generic objects.

Generic service requests

Python GET GET/POST/PUT/DELETE service request objects will be used as generic objects for new supported frameworks implementing APIs to access web services on client side.

requests

Example for GET request:

import requests
r = requests.get('https://api.github.com/events')

urllib

Example for GET request:

import urllib.request
with urllib.request.urlopen('http://python.org/') as response:
   html = response.read()

urllib2

Example for GET request:

import urllib2

req = urllib2.Request('http://python.org/')
response = urllib2.urlopen(req)
the_page = response.read()

Example for POST request.

import urllib2
import urllib

values = {'name' : 'Michael Foord',
          'location' : 'Northampton',
          'language' : 'Python' }

data = urllib.urlencode(values)

req = urllib2.Request('http://python.org/', data)
response = urllib2.urlopen(req)
the_page = response.read()
PUT and DELETE calls are not supported by the urllib2 module (Python version 2.x) by default. Workarounds to bypass this limitation are not detected by the analyzer.

urllib3

Example for GET request:

# using PoolManager
import urllib3
http = urllib3.PoolManager()
r = http.request('GET', 'http://httpbin.org/robots.txt')

# using HTTPConnectionPool
import urllib3
pool = urllib3.HTTPConnectionPool()
r = pool.request('GET', 'http://httpbin.org/robots.txt')

The urllib3 web service object is represented with the same Python GET urllib service as that used for urllib.

httplib

Example for GET request:

from httplib import HTTPConnection
def f():
    conn = HTTPConnection("www.python.org")
    conn.request("GET", "/index.html")

Example link from method "f" to the get httplib service:

http.client

Example for GET request:

from http.client import HTTPConnection
def f():
    conn = HTTPConnection("www.python.org")
    conn.request("GET", "/index.html")

In this case a Python Get Httplib Service will be generated (the httplib module from Python 2 has been renamed to http.client in Python 3).

httplib2

The following code will issue a http get to the url 'https://api.github.com/events':

import httplib2
h = httplib2.Http(".cache")
(resp, content) = h.request("https://api.github.com/events")

aiohttp

The following code will issue a http get to the url 'https://api.github.com/events':

import aiohttp
session = aiohttp.ClientSession()
res = session.get('https://api.github.com/events')

The aiohttp module can be also used in server mode, implementing web service operations

from aiohttp import web
async def handler(request):
    return web.Response(text="Welcome in Python")
app = web.Application()
app.router.add_get('/index', handler)
web.run_app(app)

In this case a Web Service Operation object associated to the function (coroutine) handler will be generated similar to the example for flask given below.

flask

Flask route annotations for web service operations (GET, PUT, POST, DELETE) are supported. In particular, any decorator with the format @prefix.route is considered as a flask annotation where prefix can be a Flask application object or blueprint object. In the following example, a default GET operation is ascribed to the function f, and the POST and PUT operations to the upload_file function:

from flask import Flask
app = Flask(__name__)
 
@app.route('/')
def f():
    return 'hello world!'
 
@app.route('/upload', methods=['POST', 'PUT'])
def upload_file()
	if request.method == 'POST':
            pass
	# ...

The link between the GET operation named after the routing URL "/"  and the called function f is represented by an arrow pointing to the function:

The name of a saved Web Service Operation object will be generated from the routing URL by adding a final slash when not present. In this example the name of the PUT and POST operations is "/upload/" after the routing url "/upload".

URL query parameters such as @app.route('/user/<username>') are supported. In this case the generated Web Service Operation object will be named as /user/{}/, as shown in the example below.

from flask import Flask
app = Flask(__name__)
 
@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username


Similarly double slashes // in flask routing URLs are transformed into /{}/. Additional backslashes inside URL query parameters of type path [ @app.route('/<path:path>') ] are not resolved (which in principle could catch any URL) so the web service will be named as a regular parameter /{}/.

The equivalent alternative to routing annotations using the Flask add_url_rule is also supported.

from flask import Flask
app = Flask(__name__)    
 
def index():
    pass
    
app.add_url_rule('/', 'index')

Plugable views are also supported for Flask add_url_rule.

from flask.views import MethodView

class InformationAPI(MethodView):

    def get(self):
        information = Information.from_data(request.data)
        ...

app.add_url_rule('/<info>/informations/', view_func=InformationAPI.as_view('informations'))

falcon

Below images are deprecated: The type Python Falcon Web Service GET operation and similar are replaced by its generic counterpart.

Falcon route annotations for web service operations (GET, PUT, POST, DELETE) are supported. 

In the following example, a default GET operation is ascribed to the function on_get from GetResourceclass,and the POST and PUT operations to the on_putandon_postfunctions fromPut_PostResourcewith two differents urls routing:

The link between the GET operation named after the routing URL "/"  and the called functionon_get is represented by an arrow pointing to the function:

The name of a saved Web Service Operation object will be generated from the routing URL by adding a final slash when not present. In this example the name of the POST operations is "/url/example/1/" and  "/url/example/2/" after the routing url "/url/example/1" and "/url/example/2".

Sinks are supported with the following rules : If no route matches a request, but the path in the requested URI matches a sink prefix, Falcon will pass control to the associated sink, regardless of the HTTP method requested. If the prefix overlaps a registered route template, the route will take precedence and mask the sink.

In this case Web Service Operation objects generated as sinks will be named as/that/, and not as/this/since another Web Service Operation object exists with an overlapping url.

importfalcon
 
app=falcon.App()
 
class GetResource():
    def on_get():
        print('on_get function')
 
def sink_method(resp,**kwargs):
    resp.body="Sink"
    pass
 
app.add_route('this/is/the/way', GetResource())
app.add_sink(sink_method, prefix='/that') # get, post, put & delete routes will be created and linked to sink_method
app.add_sink(sink_method, prefix='/this') # no routes created because Url overlaps another route

The optional suffix keyword argument of Falcon add_route is supported. In this way, multiple closely-related routes can be mapped to the same resource.

import falcon
app=falcon.App()
 
class PrefixResource(object):
 
    def on_get(self, req, resp):
         pass
 
    def on_get_foo(self, req, resp):
         pass
 
    def on_post_foo(self, req, resp):
        pass
 
    def on_delete_bar(self, req, resp):
        pass
 
app.add_route('get/without/prefix', PrefixResource())
app.add_route('get/and/post/prefix/foo', PrefixResource(), suffix='foo')
app.add_route('delete/prefix/bar', PrefixResource(), suffix='bar')

web2py

Example for GET request:

from gluon.tools import fetch
def m(self):
    page = fetch('http://www.google.com/')

Example link from method "m" to the get web2py service:

CherryPy

Supported APIs (Cherrypy)

Link Type

Caller

Callee

Remarks

@cherrypy.expose (on method)

callLink

Python Web Service Get Operation

Python Method


aliases: parameters given to decorator (on method)

callLink

Python Web Service Get Operation

Python Method

Generates extra routing URL based on aliases name

method.expose = True                                            

callLink

Python Web Service Get Operation

Python Method

Equivalent to @cherrypy.expose (on method and unexposed class)

cherrypy.quickstart

N/A

N/A

N/A

Instantiate undecorated class with page handler method (class)

Optionally alters routing URL (str)

Optionally defines configurations (dict)

@cherrypy.expose (on class)

CallLink

Python Web Service (Get/Put/Post/Delete) Operation

Python Method

Exposed classes only accept method named GET, PUT, POST and DELETE

cherrypy.dispatch.MethodDispatcher

N/A

N/A

N/A

Basic support for request.dispatcher


Example of creation of a GET operation:

import cherrypy

class StringGenerator(object):
    @cherrypy.expose
    def index(self):
        return "Hello world!"

Example link from 'exposed' method index:

The Cherrypy framework implicitly creates an extra GET operation with url "/" (in addition to "index/") when the index method is exposed.


Example of links created from combination of cherrypy.quickstart(), “exposed class” and cherrypy.dispatch.MethodDispatcher() the routing URL is defined as the key in a configuration dictionary that calls the dispatcher:

Limitation: Only the standard dispatcher "cherrypy.dispatch.MethodDispatcher()" is supported, i.e., no custom dispatcher is currently supported.

FastAPI

Summary table of Supported features for FastAPI web framework:

Supported API (FastAPI)

Link type

Caller

Callee

Remark

fastapi.FastAPI()

N/A

N/A

N/A

Supported options: root_path

fastapi.APIRouter()

N/A

N/A

N/A

Supported options: prefix

Supported API decorators
({app}: fastapi.applications.FastAPI)





@{app}.get()

CallLink

Python Web Service GET Operation

Python Method


@{app}.post()

CallLink

Python Web Service POST Operation

Python Method


@{app}.put()

CallLink

Python Web Service PUT Operation

Python Method


@{app}.delete()

CallLink

Python Web Service DELETE Operation

Python Method


Supported API decorators
({route}: fastapi.routing.APIRouter)




@{route}.get()

CallLink

Python Web Service GET Operation

Python Method


@{route}.put()

CallLink

Python Web Service PUT Operation

Python Method


@{route}.post()

CallLink

Python Web Service POST Operation

Python Method


@{route}.delete()

CallLink

Python Web Service DELETE Operation

Python Method


Basic example of GET operation with two FastAPI instances and with root_path options:

from fastapi import FastAPI
 
app1 = FastAPI()
app2 = FastAPI(root_path="/tata")
 
# regular routing 2 examples with FastAPI
# with instance app1
 
@app1.get("/")
async def HelloWorld_app1():
    return {"message": "Hello World"}
 
@app1.get("/Me")
async def HelloMe_app1():
    return {"message": "Mika"}
 
# with app2
@app2.get("/")
async def HelloWorld_app2():
    return {"message": "Hello World"}
 
@app2.get("/Me")
async def HelloMe_app2():
    return {"message": "Mika"}


Results from Enlighten:

Second example of GET operation with two APIRouter instances and with “prefix” options.

from fastapi import APIRouter
 
routeur1 = APIRouter()
routeur2 = APIRouter(prefix="/tonton")
 
# regular routing 2 examples with APIRouter
# with routeur1
@routeur1.get("/")
async def HelloWorld_routeur1():
    return {"message": "Hello World"}
 
@routeur1.get("/Me")
async def HelloMe_router1():
    return {"message": "Mika"}
 
# with routeur2
@routeur2.get("/")
async def HelloWorld_router2():
    return {"message": "Hello World"}
 
@routeur2.get("/Me")
async def HelloMe_router2():
    return {"message": "Mika"}

Results from Enlighten:

Third example of GET operation with path parameters:

from fastapi import FastAPI
 
app = FastAPI()
 
# routing with parameter value
@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}
 
@app.get("/user/{name}")
async def read_user(name:str):
    return {"name": name}

Results from Enlighten:

Fourth example with POST, PUT DELETE operation with query parameters:

from fastapi import FastAPI
 
app = FastAPI()
 
@app.post("/users/")
async def create_User(user):
    return user

@app.put("/users/")
async def update_User(user):
    return user
 
@app.delete("/users/")
async def remove_User(user):
    return user

Results from Enlighten: