REST API กลายเป็นวิธีทั่วไปในการสร้างอินเทอร์เฟซระหว่างเว็บ กลับสิ้นสุด และ ส่วนหน้า และระหว่างบริการบนเว็บต่างๆ ความเรียบง่ายของอินเทอร์เฟซประเภทนี้และการสนับสนุนโปรโตคอล HTTP และ HTTPS ที่แพร่หลายในเครือข่ายและเฟรมเวิร์กที่แตกต่างกันทำให้เป็นตัวเลือกที่ง่ายเมื่อพิจารณาถึงปัญหาการทำงานร่วมกัน
ขวด เป็นเฟรมเวิร์กเว็บ Python ที่เรียบง่าย มีน้ำหนักเบารวดเร็วและใช้งานง่ายและเหมาะอย่างยิ่งสำหรับการสร้างบริการ RESTful ก การเปรียบเทียบกระดูกเปลือย ผลิตโดย Andriy Kornatskyy จัดให้เป็นหนึ่งในกรอบงานสามอันดับแรกในแง่ของเวลาตอบสนองและปริมาณงาน (คำขอต่อวินาที) ในการทดสอบของฉันเองบนเซิร์ฟเวอร์เสมือนที่มีให้จาก DigitalOcean ฉันพบว่าการรวมกันของสแต็กเซิร์ฟเวอร์ uWSGI และขวดสามารถทำได้ต่ำถึงค่าใช้จ่าย140μsต่อคำขอ
ในบทความนี้ฉันจะอธิบายวิธีการสร้างบริการ RESTful API โดยใช้ Bottle
กรอบขวดให้ประสิทธิภาพที่น่าประทับใจในบางส่วนเนื่องจากมีน้ำหนักเบา ในความเป็นจริงไลบรารีทั้งหมดถูกแจกจ่ายเป็นโมดูลไฟล์เดียว ซึ่งหมายความว่ามันไม่ได้จับมือคุณมากเท่ากับเฟรมเวิร์กอื่น ๆ แต่ยังยืดหยุ่นกว่าและสามารถปรับให้เข้ากับสแต็คเทคโนโลยีต่างๆได้มากมาย Bottle จึงเหมาะที่สุดสำหรับโครงการที่มีประสิทธิภาพและความสามารถในการปรับแต่งได้ในระดับพรีเมี่ยมและข้อได้เปรียบในการประหยัดเวลาของเฟรมเวิร์กที่ใช้งานหนักมากกว่านั้นไม่ได้รับการพิจารณา
ความยืดหยุ่นของ Bottle ทำให้คำอธิบายเชิงลึกเกี่ยวกับการตั้งค่าแพลตฟอร์มนั้นไร้ประโยชน์เล็กน้อยเนื่องจากอาจไม่สะท้อนถึงสแต็คของคุณเอง อย่างไรก็ตามภาพรวมโดยย่อของตัวเลือกและสถานที่เรียนรู้เพิ่มเติมเกี่ยวกับวิธีการตั้งค่ามีความเหมาะสมที่นี่:
การติดตั้ง Bottle นั้นง่ายพอ ๆ กับการติดตั้งแพ็คเกจ Python อื่น ๆ ตัวเลือกของคุณคือ:
pip install bottle
ในการติดตั้ง Bottle บนสภาพแวดล้อมเสมือนจริงคุณจะต้องมีไฟล์ Virtualenv และ pip เครื่องมือ ในการติดตั้งโปรดดูที่ไฟล์ Virtualenv และ pip เอกสารแม้ว่าคุณอาจมีอยู่ในระบบของคุณแล้ว
ใน Bash สร้างสภาพแวดล้อมด้วย Python 3:
$ virtualenv -p `which python3` env
การปราบปราม -p `which python3`
พารามิเตอร์จะนำไปสู่การติดตั้งตัวแปล Python เริ่มต้นที่มีอยู่ในระบบซึ่งโดยปกติจะเป็น Python 2.7 รองรับ Python 2.7 แต่บทช่วยสอนนี้ถือว่า Python 3.4
ตอนนี้เปิดใช้งานสภาพแวดล้อมและติดตั้งขวด:
$ . env/bin/activate $ pip install bottle
แค่นั้นแหละ. ติดตั้งขวดและพร้อมใช้งาน หากคุณไม่คุ้นเคยกับ Virtualenv หรือ pip เอกสารของพวกเขาอยู่ในอันดับต้น ๆ ลองดูสิ! พวกเขาคุ้มค่า
ขวดเป็นไปตามมาตรฐานของ Python อินเทอร์เฟซเกตเวย์ของเว็บเซิร์ฟเวอร์ (WSGI) ซึ่งหมายความว่าสามารถใช้กับเซิร์ฟเวอร์ที่เข้ากันได้กับ WSGI ซึ่งรวมถึง uWSGI , ทวิสเตอร์ , Gunicorn , Apache , Amazon Beanstalk , Google App Engine , และคนอื่น ๆ.
วิธีการตั้งค่าที่ถูกต้องจะแตกต่างกันไปเล็กน้อยในแต่ละสภาพแวดล้อม Bottle แสดงวัตถุที่สอดคล้องกับอินเทอร์เฟซ WSGI และเซิร์ฟเวอร์ต้องได้รับการกำหนดค่าให้โต้ตอบกับวัตถุนี้
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีตั้งค่าเซิร์ฟเวอร์ของคุณโปรดดูเอกสารของเซิร์ฟเวอร์และเอกสารของ Bottle ที่นี่ .
Bottle เป็นฐานข้อมูลที่ไม่เชื่อเรื่องพระเจ้าและไม่สนใจว่าข้อมูลจะมาจากไหน หากคุณต้องการใช้ฐานข้อมูลในแอปของคุณ ดัชนีแพ็คเกจ Python มีตัวเลือกที่น่าสนใจหลายอย่างเช่น SQLAlchemy , PyMongo , MongoEngine , CouchDB และ โหวต สำหรับ DynamoDB คุณต้องใช้อะแดปเตอร์ที่เหมาะสมเท่านั้นเพื่อให้ทำงานร่วมกับฐานข้อมูลที่คุณเลือกได้
ตอนนี้เรามาดูวิธีสร้างแอปพื้นฐานใน Bottle สำหรับตัวอย่างโค้ดฉันจะถือว่า Python> = 3.4 อย่างไรก็ตามสิ่งที่ฉันจะเขียนในที่นี้ส่วนใหญ่จะใช้ได้กับ Python 2.7 เช่นกัน
แอพพื้นฐานใน Bottle มีลักษณะดังนี้:
import bottle app = application = bottle.default_app() if __name__ == '__main__': bottle.run(host = '127.0.0.1', port = 8000)
เมื่อฉันพูดว่าพื้นฐานฉันหมายความว่าโปรแกรมนี้ไม่มีแม้แต่“ Hello World” ให้คุณ (ครั้งสุดท้ายที่คุณเข้าถึงอินเทอร์เฟซ REST ที่ตอบว่า“ Hello World?”) คำขอ HTTP ทั้งหมดถึง 127.0.0.1:8000
จะได้รับสถานะการตอบกลับ 404 Not Found
Bottle อาจมีหลาย ๆ แอพที่สร้างขึ้น แต่เพื่อความสะดวกเราจะสร้างอินสแตนซ์แรกสำหรับคุณ นั่นคือแอปเริ่มต้น Bottle เก็บอินสแตนซ์เหล่านี้ไว้ในกองซ้อนภายในโมดูล เมื่อใดก็ตามที่คุณทำบางอย่างกับ Bottle (เช่นเรียกใช้แอปหรือแนบเส้นทาง) และไม่ได้ระบุว่าคุณกำลังพูดถึงแอปใดแอปนั้นหมายถึงแอปเริ่มต้น ในความเป็นจริง app = application = bottle.default_app()
บรรทัดไม่จำเป็นต้องมีอยู่ในแอปพื้นฐานนี้ แต่มีอยู่เพื่อให้เราสามารถเรียกใช้แอปเริ่มต้นด้วย Gunicorn, uWSGI หรือเซิร์ฟเวอร์ WSGI ทั่วไป
ความเป็นไปได้ของแอพหลายตัวอาจดูสับสนในตอนแรก แต่เพิ่มความยืดหยุ่นให้กับ Bottle สำหรับโมดูลต่างๆของแอปพลิเคชันของคุณคุณอาจสร้างแอป Bottle พิเศษโดยสร้างอินสแตนซ์คลาส Bottle อื่น ๆ และตั้งค่าด้วยการกำหนดค่าต่างๆตามต้องการ แอปต่างๆเหล่านี้สามารถเข้าถึงได้โดย URL ที่แตกต่างกันผ่านเราเตอร์ URL ของ Bottle เราจะไม่เจาะลึกเรื่องนี้ในบทแนะนำนี้ แต่ขอแนะนำให้คุณอ่านเอกสารของ Bottle ที่นี่ และ ที่นี่ .
บรรทัดสุดท้ายของสคริปต์เรียกใช้ Bottle โดยใช้เซิร์ฟเวอร์ที่ระบุ หากไม่มีการระบุเซิร์ฟเวอร์ดังกรณีนี้เซิร์ฟเวอร์เริ่มต้นคือเซิร์ฟเวอร์อ้างอิง WSGI ในตัวของ Python ซึ่งเหมาะสำหรับวัตถุประสงค์ในการพัฒนาเท่านั้น สามารถใช้เซิร์ฟเวอร์อื่นได้ดังนี้:
bottle.run(server='gunicorn', host = '127.0.0.1', port = 8000)
นี่คือน้ำตาลในเชิงไวยากรณ์ที่ให้คุณเริ่มแอปโดยเรียกใช้สคริปต์นี้ ตัวอย่างเช่นถ้าไฟล์นี้ชื่อ main.py
คุณสามารถเรียกใช้ python main.py
เพื่อเริ่มแอป ขวดถือ ค่อนข้างมีรายการเซิร์ฟเวอร์อะแดปเตอร์มากมาย ที่สามารถใช้วิธีนี้
เซิร์ฟเวอร์ WSGI บางตัวไม่มีอะแดปเตอร์ Bottle สิ่งเหล่านี้สามารถเริ่มต้นได้ด้วยคำสั่งเรียกใช้ของเซิร์ฟเวอร์เอง ตัวอย่างเช่นใน uWSGI สิ่งที่คุณต้องทำคือโทรไปที่ uwsgi
แบบนี้:
$ uwsgi --http :8000 --wsgi-file main.py
Bottle ทำให้โครงสร้างไฟล์ของแอปขึ้นอยู่กับคุณโดยสิ้นเชิง ฉันพบว่านโยบายโครงสร้างไฟล์ของฉันมีวิวัฒนาการจากโครงการหนึ่งไปอีกโครงการหนึ่ง แต่มักจะอิงตามปรัชญา MVC
แน่นอนว่าไม่มีใครต้องการเซิร์ฟเวอร์ที่ส่งคืน 404 สำหรับทุก URI ที่ร้องขอเท่านั้น ฉันสัญญากับคุณแล้วว่าเราจะสร้าง REST API ดังนั้นมาดูกันเลย
สมมติว่าคุณต้องการ สร้างอินเทอร์เฟซ ที่จัดการชุดของชื่อ ในแอปจริงคุณอาจใช้ฐานข้อมูลสำหรับสิ่งนี้ แต่สำหรับตัวอย่างนี้เราจะใช้ในหน่วยความจำ set
โครงสร้างข้อมูล.
โครงร่างของ API ของเราอาจมีลักษณะเช่นนี้ คุณสามารถวางรหัสนี้ที่ใดก็ได้ในโครงการ แต่คำแนะนำของฉันจะเป็นไฟล์ API แยกต่างหากเช่น api/names.py
from bottle import request, response from bottle import post, get, put, delete _names = set() # the set of names @post('/names') def creation_handler(): '''Handles name creation''' pass @get('/names') def listing_handler(): '''Handles name listing''' pass @put('/names/') def update_handler(name): '''Handles name updates''' pass @delete('/names/') def delete_handler(name): '''Handles name deletions''' pass
อย่างที่เราเห็นการกำหนดเส้นทางใน Bottle ทำได้โดยใช้มัณฑนากร มัณฑนากรที่นำเข้า post
, get
, put
, และ delete
ลงทะเบียนตัวจัดการสำหรับการดำเนินการทั้งสี่นี้ การทำความเข้าใจว่างานเหล่านี้สามารถแบ่งออกเป็นดังนี้:
default_app
นักตกแต่งเส้นทาง ตัวอย่างเช่น @get()
มัณฑนากรใช้ bottle.default_app().get()
ไปยังตัวจัดการdefault_app
เป็นทางลัดทั้งหมดสำหรับ route()
. ดังนั้น default_app().get('/')
เทียบเท่ากับ default_app().route(method='GET', '/')
.ดังนั้น @get('/')
เหมือนกับ @route(method='GET', '/')
ซึ่งเหมือนกับ @bottle.default_app().route(method='GET', '/')
และสามารถใช้แทนกันได้
สิ่งหนึ่งที่มีประโยชน์เกี่ยวกับ @route
มัณฑนากรคือถ้าคุณต้องการใช้ตัวจัดการเดียวกันเพื่อจัดการกับทั้งการอัปเดตและการลบออบเจ็กต์คุณสามารถส่งรายการวิธีการจัดการเช่นนี้:
@route('/names/', method=['PUT', 'DELETE']) def update_delete_handler(name): '''Handles name updates and deletions''' pass
เอาล่ะมาใช้เครื่องจัดการเหล่านี้กัน
ตัวจัดการโพสต์ของเราอาจมีลักษณะดังนี้:
import re, json namepattern = re.compile(r'^[a-zA-Zd]{1,64}$') @post('/names') def creation_handler(): '''Handles name creation''' try: # parse input data try: data = request.json() except: raise ValueError if data is None: raise ValueError # extract and validate name try: if namepattern.match(data['name']) is None: raise ValueError name = data['name'] except (TypeError, KeyError): raise ValueError # check for existence if name in _names: raise KeyError except ValueError: # if bad request data, return 400 Bad Request response.status = 400 return except KeyError: # if name already exists, return 409 Conflict response.status = 409 return # add name _names.add(name) # return 200 Success response.headers['Content-Type'] = 'application/json' return json.dumps({'name': name})
นั่นค่อนข้างมาก มาทบทวนขั้นตอนเหล่านี้ทีละส่วน
การแยกวิเคราะห์ร่างกาย
API นี้กำหนดให้ผู้ใช้โพสต์สตริง JSON ที่เนื้อหาโดยมีแอตทริบิวต์ชื่อ“ name”
request
วัตถุที่นำเข้าก่อนหน้านี้จาก bottle
ชี้ไปที่คำขอปัจจุบันและเก็บข้อมูลทั้งหมดของคำขอไว้เสมอ มัน body
แอ็ตทริบิวต์มีไบต์สตรีมของเนื้อหาคำขอซึ่งสามารถเข้าถึงได้โดยฟังก์ชันใด ๆ ที่สามารถอ่านอ็อบเจ็กต์สตรีม (เช่นการอ่านไฟล์)
request.json()
วิธีตรวจสอบส่วนหัวของคำขอประเภทเนื้อหา“ application / json” และแยกวิเคราะห์เนื้อหาว่าถูกต้องหรือไม่ หาก Bottle ตรวจพบร่างกายที่ผิดรูปแบบ (เช่นว่างเปล่าหรือมีเนื้อหาผิดประเภท) วิธีนี้จะส่งคืน None
และด้วยเหตุนี้เราจึงเพิ่ม ValueError
หากตรวจพบเนื้อหา JSON ที่ผิดรูปแบบโดยตัวแยกวิเคราะห์ JSON มันทำให้เกิดข้อยกเว้นที่เราจับและปรับใหม่อีกครั้งเป็น ValueError
การแยกวิเคราะห์และการตรวจสอบวัตถุ
หากไม่มีข้อผิดพลาดเราได้แปลงเนื้อหาของคำขอเป็นวัตถุ Python ที่อ้างอิงโดย data
ตัวแปร. หากเราได้รับพจนานุกรมที่มีคีย์ 'ชื่อ' เราจะสามารถเข้าถึงได้ผ่าน data['name']
หากเราได้รับพจนานุกรมที่ไม่มีคีย์นี้การพยายามเข้าถึงจะนำเราไปสู่ KeyError
ข้อยกเว้น หากเราได้รับสิ่งอื่นนอกเหนือจากพจนานุกรมเราจะได้รับ TypeError
ข้อยกเว้น หากข้อผิดพลาดเหล่านี้เกิดขึ้นอีกครั้งเราจะปรับใหม่เป็น ValueError
ซึ่งแสดงว่าข้อมูลป้อนเข้าไม่ถูกต้อง
ในการตรวจสอบว่าคีย์ชื่อมีรูปแบบที่ถูกต้องหรือไม่เราควรทดสอบกับ regex mask เช่น namepattern
หน้ากากที่เราสร้างขึ้นที่นี่ ถ้าคีย์ name
ไม่ใช่สตริง namepattern.match()
จะเพิ่ม TypeError
และหากไม่ตรงกันจะส่งคืน None
ด้วยมาสก์ในตัวอย่างนี้ชื่อต้องเป็นตัวอักษรและตัวเลขคละกันของ ASCII โดยไม่มีช่องว่างตั้งแต่ 1 ถึง 64 อักขระ นี่เป็นการตรวจสอบความถูกต้องอย่างง่ายและไม่ได้ทดสอบวัตถุที่มีข้อมูลขยะเป็นต้น การตรวจสอบที่ซับซ้อนและสมบูรณ์มากขึ้นอาจทำได้โดยใช้เครื่องมือเช่น FormEncode .
การทดสอบการมีอยู่
การทดสอบครั้งสุดท้ายก่อนที่จะดำเนินการตามคำขอคือชื่อที่ระบุมีอยู่แล้วในชุดหรือไม่ ในแอปที่มีโครงสร้างมากขึ้นการทดสอบนั้นควรทำโดยโมดูลเฉพาะและส่งสัญญาณไปยัง API ของเราผ่านข้อยกเว้นพิเศษ แต่เนื่องจากเรากำลังจัดการชุดโดยตรงเราจึงต้องดำเนินการที่นี่
เราส่งสัญญาณการมีอยู่ของชื่อโดยเพิ่ม KeyError
การตอบสนองข้อผิดพลาด
เช่นเดียวกับที่ออบเจ็กต์คำขอเก็บข้อมูลคำขอทั้งหมดอ็อบเจ็กต์ตอบกลับจะทำเช่นเดียวกันสำหรับข้อมูลการตอบ การตั้งค่าสถานะการตอบกลับมีสองวิธี:
response.status = 400
และ:
response.status = '400 Bad Request'
สำหรับตัวอย่างของเราเราเลือกใช้รูปแบบที่ง่ายกว่า แต่อาจใช้รูปแบบที่สองเพื่อระบุคำอธิบายข้อความของข้อผิดพลาด ภายใน Bottle จะแยกสตริงที่สองและตั้งรหัสตัวเลขให้เหมาะสม
การตอบสนองความสำเร็จ
หากขั้นตอนทั้งหมดสำเร็จเราจะดำเนินการตามคำขอโดยเพิ่มชื่อลงในชุด _names
ตั้งค่า Content-Type
ส่วนหัวการตอบกลับและส่งคืนการตอบกลับ สตริงใด ๆ ที่ส่งคืนโดยฟังก์ชันจะถือว่าเป็นเนื้อหาตอบสนองของ a 200 Success
ดังนั้นเราจึงสร้างขึ้นมาด้วย json.dumps
จากการสร้างชื่อเราจะใช้เครื่องจัดการรายชื่อ:
@get('/names') def listing_handler(): '''Handles name listing''' response.headers['Content-Type'] = 'application/json' response.headers['Cache-Control'] = 'no-cache' return json.dumps({'names': list(_names)})
การลงรายชื่อนั้นง่ายกว่ามากใช่หรือไม่? เมื่อเทียบกับการสร้างชื่อแล้วที่นี่มีอะไรให้ทำไม่มาก เพียงตั้งค่าส่วนหัวการตอบกลับและส่งคืนการแสดง JSON ของชื่อทั้งหมดเท่านี้ก็เสร็จเรียบร้อย
ตอนนี้ให้ดูวิธีใช้วิธีการอัปเดต ไม่แตกต่างจากวิธีการสร้างมากนัก แต่เราใช้ตัวอย่างนี้เพื่อแนะนำพารามิเตอร์ URI
@put('/names/') def update_handler(name): '''Handles name updates''' try: # parse input data try: data = json.load(utf8reader(request.body)) except: raise ValueError # extract and validate new name try: if namepattern.match(data['name']) is None: raise ValueError newname = data['name'] except (TypeError, KeyError): raise ValueError # check if updated name exists if oldname not in _names: raise KeyError(404) # check if new name exists if name in _names: raise KeyError(409) except ValueError: response.status = 400 return except KeyError as e: response.status = e.args[0] return # add new name and remove old name _names.remove(oldname) _names.add(newname) # return 200 Success response.headers['Content-Type'] = 'application/json' return json.dumps({'name': newname})
สคีมาเนื้อหาสำหรับการดำเนินการอัปเดตจะเหมือนกับการดำเนินการสร้าง แต่ตอนนี้เรามี oldname
ใหม่ด้วย พารามิเตอร์ใน URI ตามที่กำหนดโดยเส้นทาง @put('/names/')
ความสามัคคี + วิธีจำกัดความสูงของกล้อง
พารามิเตอร์ URI
อย่างที่คุณเห็นสัญกรณ์ของ Bottle สำหรับพารามิเตอร์ URI นั้นตรงไปตรงมามาก คุณสามารถสร้าง URI ด้วยพารามิเตอร์ได้มากเท่าที่คุณต้องการ ขวดจะดึงออกจาก URI โดยอัตโนมัติและส่งต่อไปยังตัวจัดการคำขอ:
@get('//') def handler(param1, param2): pass
การใช้ตัวตกแต่งเส้นทางแบบเรียงซ้อนคุณสามารถสร้าง URI ด้วยพารามิเตอร์เสริม:
@get('/') @get('//') def handler(param1, param2 = None) pass
นอกจากนี้ Bottle ยังอนุญาตให้ใช้ตัวกรองการกำหนดเส้นทางต่อไปนี้ใน URI:
int
จับคู่เฉพาะพารามิเตอร์ที่สามารถแปลงเป็น
int
และส่งค่าที่แปลงไปยังตัวจัดการ:@get('/') def handler(param): pass
float
เช่นเดียวกับ
int
แต่มีค่าทศนิยม:@get('/') def handler(param): pass
re
(นิพจน์ทั่วไป)จับคู่เฉพาะพารามิเตอร์ที่ตรงกับนิพจน์ทั่วไปที่กำหนด:
@get('/') def handler(param): pass
path
จับคู่ส่วนย่อยของเส้นทาง URI ด้วยวิธีที่ยืดหยุ่น:
@get('//id>') def handler(param): pass
ตรงกัน:
/x/id
, ผ่านx
เป็นparam
./x/y/id
, ผ่านx/y
เป็นparam
.
เช่นเดียวกับวิธี GET วิธี DELETE ทำให้เรามีข่าวเล็กน้อย โปรดทราบว่าการส่งคืน None
โดยไม่ต้องตั้งค่าสถานะจะส่งคืนการตอบกลับด้วยเนื้อความว่างเปล่าและรหัสสถานะ 200
@delete('/names/') def delete_handler(name): '''Handles name updates''' try: # Check if name exists if name not in _names: raise KeyError except KeyError: response.status = 404 return # Remove name _names.remove(name) return
สมมติว่าเราได้บันทึกชื่อ API ของเราเป็น api/names.py
ตอนนี้เราสามารถเปิดใช้งานเส้นทางเหล่านี้ในไฟล์แอปพลิเคชันหลัก main.py
import bottle from api import names app = application = bottle.default_app() if __name__ == '__main__': bottle.run(host = '127.0.0.1', port = 8000)
สังเกตว่าเราได้นำเข้าเฉพาะ names
โมดูล. เนื่องจากเราได้ตกแต่งวิธีการทั้งหมดด้วย URI ที่แนบมากับแอปเริ่มต้นจึงไม่จำเป็นต้องทำการตั้งค่าใด ๆ เพิ่มเติม วิธีการของเรามีอยู่แล้วพร้อมให้เข้าถึง
คุณสามารถใช้เครื่องมือเช่น Curl หรือ Postman เพื่อใช้ API และทดสอบด้วยตนเอง (หากคุณใช้ Curl คุณสามารถใช้ไฟล์ ตัวจัดรูปแบบ JSON เพื่อให้การตอบกลับดูรกน้อยลง)
เหตุผลทั่วไปอย่างหนึ่งในการสร้าง REST API คือการสื่อสารกับ JavaScript front-end ผ่าน AJAX สำหรับบางแอปพลิเคชันคำขอเหล่านี้ควรได้รับอนุญาตจากโดเมนใด ๆ ไม่ใช่เฉพาะโดเมนบ้านของ API ของคุณ โดยค่าเริ่มต้นเบราว์เซอร์ส่วนใหญ่ไม่อนุญาตให้ใช้พฤติกรรมนี้ดังนั้นให้ฉันแสดงวิธีการตั้งค่า การแบ่งปันทรัพยากรข้ามแหล่งที่มา (CORS) ในขวดเพื่อให้สิ่งนี้:
from bottle import hook, route, response _allow_origin = '*' _allow_methods = 'PUT, GET, POST, DELETE, OPTIONS' _allow_headers = 'Authorization, Origin, Accept, Content-Type, X-Requested-With' @hook('after_request') def enable_cors(): '''Add headers to enable CORS''' response.headers['Access-Control-Allow-Origin'] = _allow_origin response.headers['Access-Control-Allow-Methods'] = _allow_methods response.headers['Access-Control-Allow-Headers'] = _allow_headers @route('/', method = 'OPTIONS') @route('/', method = 'OPTIONS') def options_handler(path = None): return
hook
มัณฑนากรช่วยให้เราเรียกใช้ฟังก์ชันก่อนหรือหลังการร้องขอแต่ละครั้ง ในกรณีของเราในการเปิดใช้งาน CORS เราต้องตั้งค่า Access-Control-Allow-Origin
, -Allow-Methods
และ -Allow-Headers
ส่วนหัวสำหรับคำตอบของเรา สิ่งเหล่านี้แสดงให้ผู้ร้องขอทราบว่าเราจะให้บริการตามคำขอที่ระบุ
นอกจากนี้ไคลเอนต์อาจส่งคำขอ OPTIONS HTTP ไปยังเซิร์ฟเวอร์เพื่อดูว่าอาจส่งคำขอด้วยวิธีการอื่น ๆ หรือไม่ ด้วยตัวอย่าง catch-all ตัวอย่างนี้เราตอบสนองคำขอ OPTIONS ทั้งหมดด้วยรหัสสถานะ 200 และเนื้อความว่างเปล่า
ในการเปิดใช้งานเพียงบันทึกและนำเข้าจากโมดูลหลัก
นั่นคือทั้งหมดที่มีให้!
ด้วยบทช่วยสอนนี้ฉันได้พยายามพูดถึงขั้นตอนพื้นฐานในการสร้าง REST API สำหรับแอป Python ด้วยเว็บเฟรมเวิร์ก Bottle
คุณสามารถเพิ่มพูนความรู้ของคุณเกี่ยวกับกรอบงานขนาดเล็ก แต่ทรงพลังนี้ได้โดยไปที่ กวดวิชา และ เอกสารอ้างอิง API .
ที่เกี่ยวข้อง: การสร้าง Node.js / TypeScript REST API ตอนที่ 1: Express.js