• Aucun résultat trouvé

Server-side HTTP

N/A
N/A
Protected

Academic year: 2022

Partager "Server-side HTTP"

Copied!
72
0
0

Texte intégral

(1)

Server-side HTTP

(2)

API Creation

(3)

Create an API?

Django: Powerful web framework with a lot of modules. Great to build a complete website.

Flask: Small Framework to build simple website.

Bottle: Similar to Flask, but even simpler. Perfect to build an API

Available libraries/frameworks in Python:

(4)

Create an API

The Bottle Framework (single file module, no dependencies)

Routing: Requests to function-call mapping with support for clean and dynamic URLs.

Templates: Fast and pythonic built-in template engine

Utilities: Convenient access to form data, file

uploads, cookies, headers and other HTTP-related metadata.

Server: Built-in HTTP development server and support for other WSGI capable HTTP server.

WSGI is the Web Server Gateway Interface

(5)

Create an API

from bottle import *

@route('/hello/<name>') def index(name):

return 'Hello '+name

run(host='localhost', port=8080)

Hello world example:

(6)

Create an API

127.0.0.1 - - [05/Nov/2020 09:14:16] "GET / HTTP/1.1" 404 720

127.0.0.1 - - [05/Nov/2020 09:14:17] "GET /favicon.ico HTTP/1.1" 404

742

(7)

Create API

127.0.0.1 - - [05/Nov/2020 09:19:44] "GET /hello/S%C3%A9bastien HTTP/

1.1" 200 16

(8)

Create an API

from bottle import Bottle, run app = Bottle()

@app.route('/hello/<name>') def index(name):

return 'Hello '+name

run(app, host='localhost', port=8080)

Hello world example:

(9)

Create an API

@route('/square/<id:int>') def square(id):

Filters: :int, :float, :path, :re

/square/1

@route('/open/<filepath:path>') def open(filepath):

/open/images/sun.png

filepath

@route('/slug/<idSlug:re:[0-9]+-.*>') def slug(idSlug):

/slug/51-bottle

(10)

Create an API

@route(‘/square/<id:int>')

HTTP Request Methods

accept GET method

@post('/images')

@route('/images', method='POST') or

Same thing with PUT and DELETE

(11)

Create an API

@route('/square/<id:int>'):

def square(id):

Generating the Content:

• return no content (False, empty string, ...)

return False

• return a string

return 'Hello'


return json.dumps(dictObject)

• return a file

return open('file.ext', 'rb')


return bottle.static_file('file.ext') # Optimized by bottle

• return an iterable

return ['line1\n', 'line2\n']

yield 'line1\n'

yield 'line2\n'

(12)

Create an API

from bottle import route, response


@route('/get/<id:int>'):

def get(id):

response.content_type = 'application/json; charset=utf-8'
 return json.dumps({'id':id, 'data': ...})


When returning a string (or a string iterable), it is automatically

encoded with respect to the given content-type, since only bytes are sent back to the client.

The Bottle Response Object:

Here, the server sends a byte array encoded in utf-8, that represents

an object formatted in JSON.

(13)

Create an API

import xml.etree.ElementTree as ET root = ET.Element('root')

child = ET.SubElement(root, "child") child.text = "I'am a child"


child.set('class', 'content') print(ET.tostring(root))

# prints <root><child class='content'>I'm a child</child></root>

(14)

Create an API

from bottle import route, abort


@route('/get/<id:int>'):

def get(id):

abort(401, "Sorry, access denied.")

Sending Error:

@route('/getImage/<id:int>'):

def getImage(id):

redirect("/get/"+id)

Redirect:

(15)

API Testing

(16)

Arithmetic API

from bottle import * from json import *

@route("/add/<i:int>/<j:int>")

def add(i,j):

return dumps([i+j])

@route("/sub/<i:int>/<j:int>")

def sub(i,j):

return dumps([i-j])

@route("/mul/<i:int>/<j:int>")

def mul(i,j):

return dumps([i*j])

@route("/div/<i:int>/<j:int>")

def div(i,j):

return dumps([i//j,i%j]) run(host='localhost', port=8080)

(17)

Arithmetic API Testing

API Tester API Server

GET /add/2/2

(18)

Arithmetic API Testing

API Tester API Server

GET /add/2/2

[4]

(19)

Arithmetic API Testing

from requests import *

server_ip = "127.0.0.1"

server_port = 8080

r1 = get(f"http://{server_ip}:{server_port}/add/4/5") print(r1.text)

r2 = get(f"http://{server_ip}:{server_port}/add/

7/14")

print(r2.text)

(20)

Arithmetic API Testing

from requests import *

server_ip = "127.0.0.1"

server_port = 8080

r1 = get(f"http://{server_ip}:{server_port}/add/4/5") print(r1.text)

r2 = get(f"http://{server_ip}:{server_port}/add/

7/14")

print(r2.text)

[9] [21]

(21)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip = "127.0.0.1"

server_port = 8080 def test_add(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/add/4/5") l = loads(r1.text)

self.assertEqual(l, [9])

r1 = get(f"http://{self.server_ip}:{self.server_port}/add/2/2") l = loads(r1.text)

self.assertEqual(l, [4]) if __name__ == '__main__':

unittest.main()

(22)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip = "127.0.0.1"

server_port = 8080 def test_add(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/add/4/5") l = loads(r1.text)

self.assertEqual(l, [9])

r1 = get(f"http://{self.server_ip}:{self.server_port}/add/2/2") l = loads(r1.text)

self.assertEqual(l, [4])

if __name__ == '__main__':

unittest.main()

. --- Ran 1 test in 0.008s

OK

(23)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip,server_port = « 127.0.0.1 », 8080

def test_sub(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/4/5") l = loads(r1.text)

self.assertEqual(l, [1])

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/2/2") l = loads(r1.text)

self.assertEqual(l, [0]) if __name__ == '__main__':

unittest.main()

(24)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip,server_port = « 127.0.0.1 », 8080

def test_sub(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/4/5") l = loads(r1.text)

self.assertEqual(l, [1])

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/2/2") l = loads(r1.text)

self.assertEqual(l, [0])

if __name__ == '__main__':

unittest.main()

.F

======================================================================

FAIL: test_sub (__main__.TestAPIMethods)

--- Traceback (most recent call last):

File "/Users/tixeuil/src/bottle/bottle_unittest_1.py", line 20, in test_sub self.assertEqual(l, [1])

AssertionError: Lists differ: [-1] != [1]

First differing element 0:

-1 1

- [-1]

? - + [1]

--- Ran 2 tests in 0.010s

FAILED (failures=1)

(25)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip,server_port = « 127.0.0.1 », 8080

def test_sub(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/4/5") l = loads(r1.text)

self.assertEqual(l, [-1])

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/2/2") l = loads(r1.text)

self.assertEqual(l, [0]) if __name__ == '__main__':

unittest.main()

(26)

Arithmetic API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip,server_port = « 127.0.0.1 », 8080

def test_sub(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/4/5") l = loads(r1.text)

self.assertEqual(l, [-1])

r1 = get(f"http://{self.server_ip}:{self.server_port}/sub/2/2") l = loads(r1.text)

self.assertEqual(l, [0])

if __name__ == '__main__':

unittest.main()

..

--- -

Ran 2 tests in 0.011s

OK

(27)

String API Testing

from bottle import * from json import *

@route("/to_upper/<s>") def to_upper(s):

return dumps(s.upper())

run(host='localhost', port=8080)

(28)

String API Testing

from bottle import * from json import *

@route("/to_upper/<s>") def to_upper(s):

return dumps(s.upper())

run(host='localhost', port=8080)

(29)

String API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip, server_port = ‘127.0.0.1’, 8080 def test_to_upper(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/to_upper/sébastien") l = loads(r1.text)

self.assertEqual(l, 'SÉBASTIEN')

r1 = get(f"http://{self.server_ip}:{self.server_port}/to_upper/tixeuil") l = loads(r1.text)

self.assertEqual(l, 'TIXEUIL') if __name__ == '__main__':

unittest.main()

(30)

String API Testing

from requests import * from json import * import unittest

class TestAPIMethods(unittest.TestCase):

server_ip, server_port = ‘127.0.0.1’, 8080 def test_to_upper(self):

r1 = get(f"http://{self.server_ip}:{self.server_port}/to_upper/sébastien") l = loads(r1.text)

self.assertEqual(l, 'SÉBASTIEN')

r1 = get(f"http://{self.server_ip}:{self.server_port}/to_upper/tixeuil") l = loads(r1.text)

self.assertEqual(l, 'TIXEUIL')

if __name__ == '__main__':

unittest.main()

.

--- -

Ran 1 test in 0.009s

OK

(31)

API Using

(32)

API User is a Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

'''

(33)

API User is a Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

'''

(34)

API User is a Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

i = request.forms['i']

j = request.forms['j']

r = get(f"http://{server_ip}:

{server_port}/add/{i}/{j}") l = loads(r.text)

return f"<h1>{i}+{j}={l[0]}</h1>"

run(host='localhost', port=8081)

(35)

API User is a Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

i = request.forms['i']

j = request.forms['j']

r = get(f"http://{server_ip}:

{server_port}/add/{i}/{j}") l = loads(r.text)

return f"<h1>{i}+{j}={l[0]}</h1>"

run(host='localhost', port=8081)

(36)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

(37)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

(38)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

POST /input, i=2, j=2

(39)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

POST /input, i=2, j=2

GET /add/2/2

(40)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

POST /input, i=2, j=2

GET /add/2/2

[4]

(41)

API User is a Bottle Web Server

Web Client Web Server

API User API Server

GET /input

<form action="/input" method="post">

i: <input name="i" type="text" />

j: <input name="j" type="text" />

<input value="Add" type="submit" />

</form>

POST /input, i=2, j=2

GET /add/2/2

[4]

<h1>2+2=4</h1>

(42)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

(43)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

(44)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

s = request.forms[’s’]

r = get(f"http://{server_ip}:

{server_port}/to_upper/{s}") l = loads(r.text)

return f"<h1>{s}.upper()={l}</h1>"

run(host='localhost', port=8081)

(45)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

s = request.forms[’s’]

r = get(f"http://{server_ip}:

{server_port}/to_upper/{s}") l = loads(r.text)

return f"<h1>{s}.upper()={l}</h1>"

run(host='localhost', port=8081)

(46)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

s = request.forms.getunicode('s') r = get(f"http://{server_ip}:

{server_port}/to_upper/{s}") l = loads(r.text)

return f"<h1>{s}.upper()={l}</h1>"

run(host='localhost', port=8081)

(47)

API User is a

Bottle Web Server

from bottle import route, request, run from json import *

from requests import get

server_ip = "127.0.0.1"

server_port = 8080

@route("/input") def input():

return '''

<form action="/input" method="post">

Word: <input name="s" type="text" />

<input value="To Uppercase" type="submit" />

</form>

'''

@route("/input", method='POST') def do_input():

s = request.forms.getunicode('s') r = get(f"http://{server_ip}:

{server_port}/to_upper/{s}") l = loads(r.text)

return f"<h1>{s}.upper()={l}</h1>"

run(host='localhost', port=8081)

(48)

from bottle import route, response, request


@route('/getAll'):

def getAll():


# catch params in the url: /getAll?order=name order = request.query['order']


# catch params sent by forms (with POST method) order = request.forms['order'] 


# catch all params (sent by forms or in the url) order = request.params['order'] 


# catch files sent by forms (with POST method)
 image = request.files['image'] 


image.save('images/uploaded')

API User is a

Bottle Web Server

(49)

Using Templates

(50)

Simple Templates

from bottle import SimpleTemplate, template

tpl = SimpleTemplate('Hello {{name}}!') s = tpl.render(name='World')

print(s)

(51)

Simple Templates

from bottle import SimpleTemplate, template

tpl = SimpleTemplate('Hello {{name}}!') s = tpl.render(name='World')

print(s) Hello World!

(52)

Simple Templates

from bottle import SimpleTemplate, template

s = template('Hello {{name}}!',name='World') print(s)

my_dict={'number': '123', 'street': 'Fake St.', 'city':

'Fakeville'}

s = template('The address is at {{number}} {{street}}, {{city}}', my_dict)

print(s)

(53)

Simple Templates

from bottle import SimpleTemplate, template

s = template('Hello {{name}}!',name='World') print(s)

my_dict={'number': '123', 'street': 'Fake St.', 'city':

'Fakeville'}

s = template('The address is at {{number}} {{street}}, {{city}}', my_dict)

print(s)

Hello World!

The address is at 123 Fake St., Fakeville

(54)

If Condition

from bottle import SimpleTemplate, template

s = template('Hello {{name if name != "World" else

"Planet"}}!',name='World') print(s)

s = template('Hello {{name if name != "World" else

"Planet"}}!',name='Sébastien')

print(s)

(55)

If Condition

from bottle import SimpleTemplate, template

s = template('Hello {{name if name != "World" else

"Planet"}}!',name='World') print(s)

s = template('Hello {{name if name != "World" else

"Planet"}}!',name='Sébastien') print(s)

Hello Planet!

Hello Sébastien!

(56)

Beware HTML

from bottle import SimpleTemplate, template

s = template('Hello {{name}}!',name='<b>World</b>') print(s)

s = template('Hello {{!name}}!',name='<b>World</

b>')

print(s)

(57)

Beware HTML

from bottle import SimpleTemplate, template

s = template('Hello {{name}}!',name='<b>World</b>') print(s)

s = template('Hello {{!name}}!',name='<b>World</

b>')

print(s)

Hello &lt;b&gt;World&lt;/b&gt;!

Hello <b>World</b>!

(58)

Template Files

<html>

<head><title>{{title}}</title></head>

<body>

<h1>{{title}}</h1>

{{content}}

</body>

</html>

simple.tpl

(59)

Template Files

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'content': 'This is the content'}

s = template('simple.tpl',site)

print(s)

(60)

Template Files

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'content': 'This is the content'}

s = template('simple.tpl',site) print(s)

<html>

<head><title>This is the title</title></head>

<body>

<h1>This is the title</h1>

This is the content </body>

</html>

(61)

Template Files Conditionals

<html>

<head><title>{{title}}</title></head>

<body>

<h1>{{title}}</h1>

% if bold_content:

<b>

% end

{{content}}

% if bold_content:

</b>

% end </body>

</html>

simple_if.tpl

(62)

Template Files Conditionals

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'content': 'This is the content'}

s = template(‘simple_if.tpl',site, bold_content=True)

print(s)

(63)

Template Files Conditionals

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'content': 'This is the content'}

s = template(‘simple_if.tpl',site, bold_content=True)

print(s)

<html>

<head><title>This is the title</title></head>

<body>

<h1>This is the title</h1>

<b> This is the content </b>

</body>

</html>

(64)

Template Files Conditionals

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'content': 'This is the content'}

s = template(‘simple_if.tpl',site, bold_content=False)

print(s)

<html>

<head><title>This is the title</title></head>

<body>

<h1>This is the title</h1>

This is the content </body>

</html>

(65)

Template Files Loops

<html>

<head><title>{{title}}</title></head>

<body>

<h1>{{title}}</h1><ul>

% for content in contents:

% if bold_content:

<li><b>{{content}}</b></li>

% else:

<li>{{content}}</li>

% end %end

</ul></body>

</html>

simple_for.tpl

(66)

Template Files Loops

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'contents': ['This is the first line of content', 'second line', 'third line']}

s = template(‘simple_for.tpl', site, bold_content=True)

print(s)

(67)

Template Files Loops

from bottle import SimpleTemplate, template

site = { 'title': 'This is the title', 'contents': ['This is the first line of content', 'second line', 'third line']}

s = template(‘simple_for.tpl', site, bold_content=True)

print(s)

<html>

<head><title>This is the title</title></head>

<body>

<h1>This is the title</h1><ul>

<li><b>This is the first line of content</b></li>

<li><b>second line</b></li>

<li><b>third line</b></li>

</ul></body>

</html>

(68)

Asynchronous Server

(69)

All your code runs in the same thread (no need to restrict access to shared memory, low overhead)

gevent creates a lots of greenbelt objects, which are like small and really cheap threads. greenlets may be run concurrently in one or more thread.

The code executed is switched automatically by 
 gevent when a blocking function is called.

Asynchronous Applications

(70)

146

getImage(1)

readfile()

Synchronous:

Asynchronous:

getImage(2)

readfile()

getImage(1)

readfile()

getImage(2)

readfile()

main thread

main thread

(71)

Asynchronous Server

from gevent import monkey; monkey.patch_all() from time import sleep

from bottle import route, run

@route('/stream') def stream():

yield 'START' sleep(3)

yield 'MIDDLE' sleep(5)

yield 'END'

run(host='0.0.0.0', port=8080, server='gevent')

(72)

Asynchronous Application

Références

Documents relatifs

Every processing element in a CS-2 system has its own dedicated interface to the communications network; a Meiko designed communications processor.. The

Specifying fonts If you created your own .Xdefaults-hostname file during a session, and you want the new font values applied to clients that are currently running, you

This is a SQL Server–generated name for a primary key on the Employees table of the Accounting database, which we will create later in the chapter — the PK is for primary key (which

The following example uses the xml data type to return the results of a SELECT statement in this function.. The return value is set as the xml data type, which is then returned

Although MSDE is compatible with all other versions of SQL Server 2000 and thus makes an excellent development tool in a stand-alone environment, the absence of administrative

SQL Server 2005 ofrece una plataforma de datos más confiable, segura y SQL Server 2005 ofrece una plataforma de datos más confiable, segura y productiva para aplicaciones de unidad

• Si vous pensez installer un serveur Java (comme Tomcat) et Cocoon (XML publishing framework), sachez Xalan et Xerces sont distribubés avec Cocoon Note pour ceux qui veulent

Subscriber’s smartcard contains his profile, his current applications table (AIT) and their. associated secure