การสร้าง Rest API ด้วย Bottle Framework

เผยแพร่แล้ว: 2022-03-11

REST API ได้กลายเป็นวิธีทั่วไปในการสร้างอินเทอร์เฟซระหว่างส่วนหลังของเว็บและส่วนหน้า และระหว่างบริการเว็บต่างๆ ความเรียบง่ายของอินเทอร์เฟซประเภทนี้ และการรองรับโปรโตคอล HTTP และ HTTPS ที่แพร่หลายในเครือข่ายและเฟรมเวิร์กต่างๆ ทำให้เป็นตัวเลือกที่ง่ายเมื่อพิจารณาถึงปัญหาด้านการทำงานร่วมกัน

Bottle เป็นเฟรมเวิร์กเว็บ Python ที่เรียบง่าย มีน้ำหนักเบา รวดเร็ว และใช้งานง่าย และเหมาะสำหรับการสร้างบริการ RESTful การเปรียบเทียบโดยเปล่าประโยชน์โดย Andriy Kornatskyy จัดให้มันเป็นหนึ่งในสามเฟรมเวิร์กอันดับต้น ๆ ในแง่ของเวลาตอบสนองและปริมาณงาน (คำขอต่อวินาที) ในการทดสอบของฉันเองบนเซิร์ฟเวอร์เสมือนที่มีให้จาก DigitalOcean ฉันพบว่าการรวมกันของสแต็กเซิร์ฟเวอร์ uWSGI และ Bottle สามารถบรรลุถึงค่าโสหุ้ย140μsต่อคำขอ

ในบทความนี้ ผมจะอธิบายวิธีสร้างบริการ RESTful API โดยใช้ Bottle

ขวด: Python Web Framework ที่เร็วและน้ำหนักเบา

การติดตั้งและการกำหนดค่า

เฟรมเวิร์ก Bottle บรรลุประสิทธิภาพที่น่าประทับใจในส่วนหนึ่งเนื่องจากน้ำหนักเบา อันที่จริง ไลบรารีทั้งหมดถูกแจกจ่ายเป็นโมดูลไฟล์เดียว ซึ่งหมายความว่ามันไม่ได้จับมือคุณมากเท่ากับเฟรมเวิร์กอื่น ๆ แต่ก็มีความยืดหยุ่นมากกว่าและสามารถปรับให้เข้ากับสแต็คเทคโนโลยีที่แตกต่างกันมากมาย ดังนั้น Bottle จึงเหมาะที่สุดสำหรับโครงการที่ประสิทธิภาพและความสามารถในการปรับแต่งอยู่ในระดับสูง และเมื่อข้อดีที่ช่วยประหยัดเวลาของเฟรมเวิร์กสำหรับงานหนักที่มากกว่านั้นไม่ได้นำมาพิจารณา

ความยืดหยุ่นของ Bottle ทำให้คำอธิบายเชิงลึกเกี่ยวกับการตั้งค่าแพลตฟอร์มนั้นไร้ประโยชน์เล็กน้อย เนื่องจากอาจไม่ได้สะท้อนถึงสแต็กของคุณเอง อย่างไรก็ตาม ภาพรวมโดยย่อของตัวเลือกต่างๆ และที่ที่จะเรียนรู้เพิ่มเติมเกี่ยวกับวิธีตั้งค่านั้น มีความเหมาะสมที่นี่:

การติดตั้ง

การติดตั้ง Bottle นั้นง่ายเหมือนกับการติดตั้งแพ็คเกจ Python อื่นๆ ตัวเลือกของคุณคือ:

  • ติดตั้งบนระบบของคุณโดยใช้ตัวจัดการแพ็คเกจของระบบ Debian Jessie (ความเสถียรปัจจุบัน) ทำแพ็คเกจเวอร์ชัน 0.12 เป็น python-bottle
  • ติดตั้งบนระบบของคุณโดยใช้ Python Package Index พร้อม 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

ตอนนี้เปิดใช้งานสภาพแวดล้อมและติดตั้ง Bottle:

 $ . env/bin/activate $ pip install bottle

แค่นั้นแหละ. ติดตั้งขวดแล้วพร้อมใช้งาน หากคุณไม่คุ้นเคยกับ virtualenv หรือ pip เอกสารประกอบของพวกเขานั้นยอดเยี่ยม ลองดูสิ! พวกเขาคุ้มค่า

เซิร์ฟเวอร์

Bottle สอดคล้องกับ Web Server Gateway Interface (WSGI) มาตรฐานของ Python ซึ่งหมายความว่าสามารถใช้กับเซิร์ฟเวอร์ใด ๆ ที่สอดคล้องกับ WSGI ซึ่งรวมถึง uWSGI, Tornado, Gunicorn, Apache, Amazon Beanstalk, Google App Engine และอื่นๆ

วิธีที่ถูกต้องในการตั้งค่าจะแตกต่างกันไปเล็กน้อยตามแต่ละสภาพแวดล้อม Bottle แสดงวัตถุที่สอดคล้องกับอินเทอร์เฟซ WSGI และต้องกำหนดค่าเซิร์ฟเวอร์เพื่อโต้ตอบกับวัตถุนี้

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการตั้งค่าเซิร์ฟเวอร์ของคุณ โปรดดูเอกสารของเซิร์ฟเวอร์และเอกสารของ Bottle ที่นี่

ฐานข้อมูล

Bottle เป็นฐานข้อมูลที่ไม่เชื่อเรื่องพระเจ้าและไม่สนใจว่าข้อมูลมาจากไหน หากคุณต้องการใช้ฐานข้อมูลในแอปของคุณ ดัชนีแพ็คเกจ Python มีตัวเลือกที่น่าสนใจมากมาย เช่น SQLAlchemy, PyMongo, MongoEngine, CouchDB และ Boto สำหรับ 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 ที่ตอบว่า "สวัสดีชาวโลก?") คำขอ 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 เพื่อเริ่มแอปได้ Bottle มีรายการเซิร์ฟเวอร์อะแดปเตอร์มากมายที่สามารถใช้ได้ในลักษณะนี้

เซิร์ฟเวอร์ WSGI บางตัวไม่มีอะแดปเตอร์ขวด สิ่งเหล่านี้สามารถเริ่มต้นด้วยคำสั่งรันของเซิร์ฟเวอร์เอง ตัวอย่างเช่น บน uWSGI สิ่งที่คุณต้องทำคือเรียก uwsgi ดังนี้:

 $ uwsgi --http :8000 --wsgi-file main.py

หมายเหตุเกี่ยวกับโครงสร้างไฟล์

Bottle ปล่อยให้โครงสร้างไฟล์ของแอปขึ้นอยู่กับคุณ ฉันพบว่านโยบายโครงสร้างไฟล์ของฉันมีวิวัฒนาการจากโปรเจ็กต์หนึ่งไปอีกโปรเจ็กต์ แต่มักจะอิงตามปรัชญาของ MVC

สร้าง REST API ของคุณ

แน่นอนว่าไม่มีใครต้องการเซิร์ฟเวอร์ที่ส่งคืน 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/<name>') def update_handler(name): '''Handles name updates''' pass @delete('/names/<name>') def delete_handler(name): '''Handles name deletions''' pass

การกำหนดเส้นทาง

อย่างที่เราเห็น การกำหนดเส้นทางใน Bottle ทำได้โดยใช้มัณฑนากร มัณฑนากรที่นำเข้า post , get , put และ delete register handler สำหรับการกระทำทั้งสี่นี้ ทำความเข้าใจว่างานเหล่านี้สามารถแบ่งออกได้ดังนี้:

  • มัณฑนากรทั้งหมดข้างต้นเป็นทางลัดไปยังผู้ตกแต่งการกำหนดเส้นทาง 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/<name>', method=['PUT', 'DELETE']) def update_delete_handler(name): '''Handles name updates and deletions''' pass

เอาล่ะ เรามาปรับใช้ตัวจัดการเหล่านี้กัน

สร้าง REST API ที่สมบูรณ์แบบของคุณด้วย Bottle Framework

RESTful API คือส่วนสำคัญของการพัฒนาเว็บสมัยใหม่ ให้บริการไคลเอ็นต์ API ของคุณด้วยการปรุงที่มีประสิทธิภาพด้วย Back-end ของขวด
ทวีต

POST: การสร้างทรัพยากร

ตัวจัดการ POST ของเราอาจมีลักษณะดังนี้:

 import re, json namepattern = re.compile(r'^[a-zA-Z\d]{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 ที่ส่วนเนื้อหาด้วยแอตทริบิวต์ชื่อ "ชื่อ"

ออบเจ็กต์ request ที่นำเข้าก่อนหน้านี้จาก bottle จะชี้ไปที่คำขอปัจจุบันเสมอและเก็บข้อมูลคำขอทั้งหมด แอตทริบิวต์ของ body มีสตรีมไบต์ของเนื้อหาคำขอ ซึ่งสามารถเข้าถึงได้โดยฟังก์ชันใดๆ ที่สามารถอ่านวัตถุสตรีมได้ (เช่น การอ่านไฟล์)

เมธอด request.json() จะตรวจสอบส่วนหัวของคำขอสำหรับประเภทเนื้อหา “application/json” และแยกวิเคราะห์เนื้อหาว่าถูกต้องหรือไม่ หาก Bottle ตรวจพบเนื้อหาที่มีรูปแบบไม่ถูกต้อง (เช่น ว่างเปล่าหรือมีเนื้อหาผิดประเภท) เมธอดนี้จะส่งคืน None และด้วยเหตุนี้เราจึงเพิ่ม ValueError หากโปรแกรมแยกวิเคราะห์ JSON ตรวจพบเนื้อหา JSON ที่มีรูปแบบไม่ถูกต้อง มันทำให้เกิดข้อยกเว้นที่เราจับและเพิ่มอีกครั้งในฐานะ ValueError

การแยกวิเคราะห์อ็อบเจ็กต์และการตรวจสอบความถูกต้อง

หากไม่มีข้อผิดพลาด เราได้แปลงเนื้อหาของคำขอเป็นวัตถุ Python ที่อ้างอิงโดยตัวแปร data หากเราได้รับพจนานุกรมที่มีคีย์ "ชื่อ" เราจะสามารถเข้าถึงได้ผ่าน data['name'] หากเราได้รับพจนานุกรมที่ไม่มีคีย์นี้ การพยายามเข้าถึงพจนานุกรมจะนำเราไปสู่ข้อยกเว้น KeyError หากเราได้รับสิ่งอื่นที่ไม่ใช่พจนานุกรม เราจะได้รับข้อยกเว้น TypeError หากข้อผิดพลาดใด ๆ เกิดขึ้น เราจะเพิ่มเป็น ValueError อีกครั้ง ซึ่งแสดงว่าอินพุตไม่ถูกต้อง

ในการตรวจสอบว่าคีย์ชื่อมีรูปแบบที่ถูกต้องหรือไม่ เราควรทดสอบกับมาสก์ regex เช่น namepattern mask ที่เราสร้างขึ้นที่นี่ หาก name คีย์ไม่ใช่สตริง namepattern.match() จะเพิ่ม TypeError และหากไม่ตรงกันก็จะคืนค่า None

ในตัวอย่างนี้มาสก์ ชื่อต้องเป็นตัวอักษรและตัวเลข ASCII โดยไม่มีช่องว่างตั้งแต่ 1 ถึง 64 อักขระ นี่เป็นการตรวจสอบอย่างง่าย และไม่ได้ทดสอบวัตถุที่มีข้อมูลขยะ เป็นต้น การตรวจสอบที่ซับซ้อนและสมบูรณ์ยิ่งขึ้นสามารถทำได้ผ่านการใช้เครื่องมือเช่น FormEncode

การทดสอบเพื่อการดำรงอยู่

การทดสอบครั้งสุดท้ายก่อนทำตามคำขอคือมีชื่อที่ระบุอยู่ในชุดแล้วหรือไม่ ในแอปที่มีโครงสร้างมากขึ้น การทดสอบนั้นน่าจะทำโดยโมดูลเฉพาะและส่งสัญญาณไปยัง API ของเราผ่านข้อยกเว้นพิเศษ แต่เนื่องจากเรากำลังจัดการชุดโดยตรง เราจึงต้องดำเนินการที่นี่

เราส่งสัญญาณการมีอยู่ของชื่อโดยการเพิ่ม KeyError

การตอบสนองต่อข้อผิดพลาด

เช่นเดียวกับที่วัตถุคำขอเก็บข้อมูลคำขอทั้งหมด วัตถุตอบสนองก็ทำเช่นเดียวกันสำหรับข้อมูลการตอบกลับ มีสองวิธีในการตั้งค่าสถานะการตอบกลับ:

 response.status = 400

และ:

 response.status = '400 Bad Request'

สำหรับตัวอย่างของเรา เราเลือกใช้แบบฟอร์มที่ง่ายกว่า แต่แบบฟอร์มที่สองอาจใช้เพื่อระบุคำอธิบายข้อความของข้อผิดพลาด ภายใน Bottle จะแยกสตริงที่สองและตั้งค่ารหัสตัวเลขอย่างเหมาะสม

การตอบสนองความสำเร็จ

หากขั้นตอนทั้งหมดสำเร็จ เราจะดำเนินการตามคำขอโดยเพิ่มชื่อให้กับชุด _names การตั้งค่าหัวข้อการตอบกลับ Content-Type และส่งคืนการตอบกลับ สตริงใดๆ ที่ส่งคืนโดยฟังก์ชันจะถือเป็นเนื้อหาการตอบกลับของการตอบกลับ 200 Success รายการ ดังนั้นเราจึงสร้างสตริงขึ้นมาด้วย json.dumps

GET: รายการทรัพยากร

ต่อจากการสร้างชื่อ เราจะใช้ตัวจัดการรายชื่อ:

 @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 เท่านี้ก็เสร็จเรียบร้อย

PUT: อัปเดตทรัพยากร

ตอนนี้ มาดูวิธีการใช้วิธีการอัพเดตกัน มันไม่ได้แตกต่างจากวิธีการสร้างมากนัก แต่เราใช้ตัวอย่างนี้เพื่อแนะนำพารามิเตอร์ URI

 @put('/names/<oldname>') 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/<oldname>')

พารามิเตอร์ URI

อย่างที่คุณเห็น สัญกรณ์ของ Bottle สำหรับพารามิเตอร์ URI นั้นตรงไปตรงมามาก คุณสามารถสร้าง URI ด้วยพารามิเตอร์ได้มากเท่าที่คุณต้องการ Bottle จะแยกจาก URI โดยอัตโนมัติและส่งผ่านไปยังตัวจัดการคำขอ:

 @get('/<param1>/<param2>') def handler(param1, param2): pass

เมื่อใช้ตัวตกแต่งเส้นทางแบบเรียงซ้อน คุณสามารถสร้าง URI ด้วยพารามิเตอร์ทางเลือก:

 @get('/<param1>') @get('/<param1>/<param2>') def handler(param1, param2 = None) pass

นอกจากนี้ Bottle ยังอนุญาตให้ใช้ตัวกรองการกำหนดเส้นทางต่อไปนี้ใน URI:

  • int

จับคู่เฉพาะพารามิเตอร์ที่สามารถแปลงเป็น int และส่งผ่านค่าที่แปลงแล้วไปยังตัวจัดการ:

 @get('/<param:int>') def handler(param): pass
  • float

เช่นเดียวกับ int แต่มีค่าทศนิยม:

 @get('/<param:float>') def handler(param): pass
  • re (นิพจน์ปกติ)

จับคู่เฉพาะพารามิเตอร์ที่ตรงกับนิพจน์ทั่วไปที่กำหนด:

 @get('/<param:re:^[az]+$>') def handler(param): pass
  • path

จับคู่ส่วนย่อยของเส้นทาง URI ด้วยวิธีที่ยืดหยุ่น:

 @get('/<param:path>/id>') def handler(param): pass

แมตช์:

  • /x/id ผ่าน x เป็น param
  • /x/y/id ผ่าน x/y เป็น param

DELETE: การลบทรัพยากร

เช่นเดียวกับวิธี GET วิธี DELETE ทำให้เราทราบข่าวเล็กน้อย โปรดทราบว่าการส่งคืน None โดยไม่ตั้งค่าสถานะจะส่งคืนการตอบกลับด้วยเนื้อหาที่ว่างเปล่าและรหัสสถานะ 200

 @delete('/names/<name>') 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 ของเราเป็น 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 ที่แนบกับแอปเริ่มต้น จึงไม่ต้องทำการตั้งค่าใดๆ เพิ่มเติม วิธีการของเรามีอยู่แล้ว พร้อมที่จะเข้าถึง

ไม่มีอะไรทำให้ front-end มีความสุขเท่ากับ REST API ที่พัฒนามาอย่างดี ทำงานเหมือนมีเสน่ห์!

คุณสามารถใช้เครื่องมืออย่างเช่น Curl หรือ Postman เพื่อใช้ API และทดสอบด้วยตนเอง (หากคุณใช้ Curl คุณสามารถใช้ตัวจัดรูปแบบ JSON เพื่อทำให้การตอบสนองดูรกน้อยลง)

โบนัส: การแบ่งปันทรัพยากรข้าม Origin (CORS)

สาเหตุทั่วไปประการหนึ่งในการสร้าง REST API คือการสื่อสารกับส่วนหน้าของ JavaScript ผ่าน AJAX สำหรับบางแอปพลิเคชัน คำขอเหล่านี้ควรได้รับอนุญาตให้มาจากโดเมนใดก็ได้ ไม่ใช่แค่โดเมนเริ่มต้นของ API ของคุณ โดยค่าเริ่มต้น เบราว์เซอร์ส่วนใหญ่ไม่อนุญาตการทำงานนี้ ดังนั้นให้ฉันแสดงวิธีตั้งค่าการแชร์ทรัพยากรข้ามต้นทาง (CORS) ใน Bottle เพื่ออนุญาตสิ่งนี้:

 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('/<path:path>', 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