فریمورک فلسک (Flask) یکی از فریمورکهای محبوب برای ساخت اپلیکیشنهای وب و APIها است. این فریمورک مجموعهای از عملکردهای پایهای را در اختیار توسعهدهندهها قرار میدهد، اما طوری طراحی شده که میتوان بسته به نیاز پروژه یا شخص آن را توسعه داد. در این پست با هم نحوه ساخت یک REST API با استفاده فلسک را به شما آموزش میدهیم. اما اگر دوست دارید نحوه ساخت API با استفاده از پایتون را یاد بگیرید توصیه می کنم پست قبلی را ببینید:
این API که امروز آن را میسازیم، قرار است اطلاعاتی در مورد زبانهای مختلف برنامهنویسی را در اختیار کاربران قرار دهد. دادههای این API از تحقیق هیلل وین (Hillel Wayne) با موضوع زبانهای برنامهنویسی تاثیر گذار گرفته شده است. در پایان این آموزش API ساختهشده توسط شما به کاربران اجازه میدهد تا اعمال زیر را انجام دهند:
- دریافت تمام زبانهای برنامهنویسی ذخیره شده در API (دستور GET)
- دریافت یک داده از یک زبان برنامهنویسی (دستور GET)
- فیلتر کردن دادههای زبانهای برنامهنویسی بر اساس سال انتشار
- استفاده از دستورات POST، PUT و DELETE برای ایجاد تغییر در دادههای API
نکته: دستورات GET، POST، PUT و DELETE در واقع متدهای درخواست HTTP هستند که برای انجام یک عمل خاص بر روی داده استفاده میشوند.
چطور با استفاده از فلسک اندپوینتهای REST API را بسازیم؟
پروتکل REST به کلاینتها اجازه دسترسی به دادههای ذخیرهشده در پایگاه داده و انجام عمل بر روی این دادهها را میدهد. این دستورات را با نام CRUD (مخفف عبارتهای Create، Read، Update، Delete) میشناسند. در ادامه نحوه ساخت دستورات CRUD برای API فلسک خودتان را یاد میگیرید.
نصب فلسک
نکته: در این قسمت از ابزار virtualenv برای ساخت یک محیط مجازی بر روی سیستم شما استفاده میشود.
یک دایرکتوری برای ذخیره کدها بسازید و وارد آن شوید:
۱ |
mkdir example_app && cd example_app |
داخل دایرکتوری example_app، یک فایل با نام prog_lang_app.py بسازید:
۱ ۲ ۳ ۴ |
mkdir example_app && cd example_app touch prog_lang_app.py |
با استفاده از دستور زیر یک محیط مجازی را ایجاد و فعال کنید:
۱ ۲ ۳ |
python3 -m venv venv . venv/bin/activate |
برای اجاری یک سرور فلسک، ابتدا باید با استفاده از دستور pip فلسک را نصب کنید:
۱ ۲ |
pip install flask |
ساخت اندپونیت لیست (List Endpoint) در فلسک
سرویسهیا RESTful به طور معمول دو اندپوینت برای دریافت دادهها (GET) دارند. یکی از اندپوینتها همه دادهها را لیست کرده و یا بر اساس ویژگیهای خاصی آنها را فیلتر میکند. دومین اندپوینت جزییات یک داده خاص را دریافت میکند. در ادامه، شما دو اندپوینت برای دریافت دادهها در API خود میسازید. برای راحتی کار نام این اندپوینتها را list و details میگذاریم.
نکته: تمام دستورات زیر فایل prog_lang_app.py را ویرایش می کند.
در ادیتور کد خودتان فایل prog_lang_app.py را باز کرده و کدهای زیر را به آن اضافه کنید:
۱ ۲ ۳ ۴ |
from flask import Flask app = Flask(__name__) |
این کدها فلسک را ایمپورت کرده و اپلیکیشن را نمونهسازی می کند. شما می توانید کلاس Flask را نمونهسازی کنید و آن را به یک متغیر تخصیص دهید.
نکته: هرچند REST APIها به طور معمول داده را از پایگاه داده دریافت میکنند، اما این آموزش جزییات یکپارچهسازی با پایگاه داده را پوشش نمیدهد.
یک منبع داده درونحافظهای کوچک برای ذخیره دادههای مربوط به زبان برنامهنویسی بسازید. کدهای زیر را زیر کدهای ایمپورت و نمونهسازی اپلیکیشن قرار دهید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ |
... in_memory_datastore = { "COBOL" : {"name": "COBOL", "publication_year": ۱۹۶۰, "contribution": "record data"}, "ALGOL" : {"name": "ALGOL", "publication_year": ۱۹۵۸, "contribution": "scoping and nested functions"}, "APL" : {"name": "APL", "publication_year": ۱۹۶۲, "contribution": "array processing"}, } |
این کد منبع in_memory_datastore با دادههای سه زبان برنامهنویسی میسازد.
هر دیکشنری زبان برنامهنویسی شامل کلیدهایی برای نام، سال انتشار و نحوه مشارکت آن در طراحی زبانهای برنامهنویسی مدرن است.
اندپوینت list را با استفاده از دستور زیر بسازید. زیر دیکشنری in-memory datastore، اندپوینت list دادههای زبانهای برنامهنویسی را دریافت و در قالب یک فایل JSON نمایش میدهد.
۱ ۲ ۳ ۴ ۵ |
... @app.get('/programming_languages') def list_programming_languages(): return {"programming_languages":list(in_memory_datastore.values())} |
درخواستها با استفاده از دستور GET به آدرس programming_languages/ ارسال میکنند. این درخواست باید بدون پارامتر ارسال شود. در پاسخ درخواست نیز یک آبجکت JSON با کلید programming_languages ارسال میشود. این کلید رکوردها را نشان میدهد و در قالب یک آرایه نماش داده میشود.
اپلیکیشن را اجرا کنید تا داده بازگشت دادهشده توسط اندپوینت list را ببینید. به دایرکتوری که اپ را در آن ذخیره کردهاید بروید و دستور زیر را اجرا کنید:
۱ ۲ ۳ |
export FLASK_APP=prog_lang_app.py flask run |
مرورگر خودتان را باز کنید و به آدرس http://127.0.0.1:5000 بروید تا اپلیکیشن را به صورت لوکال روی سیستم خودتان اجرا کنید.
اگر به آدرس http://127.0.0.1:5000/programming_languages بروید، میتوانید آبجکت JSON که حاوی دادههای پایگاه داده است را ببینید.
ساخت اندپیونت Detail در فلسک
گام بعدی اضافه کردن یک اندپوینت برای دریافت جزییات داده یک زبان برنامهنویسی خاص است. اندپوینت details دارای یک متغیر با نام programming_language_id است. این متغیر به شما اجازه میدهد تا یک آیتم خاص در پایگاه داده دسترسی داشته باشید. Id اشاره شده در این متغیر، شماره ایندکس متغیر در مخزن زبان برنامهنویسی است.
با اضافه کردن کد زیر به فایل prog_lang_app.py آن را بهروزرسانی کنید:
۱ ۲ ۳ ۴ ۵ ۶ |
... @app.route('/programming_languages/<programming_language_name>') def get_programming_language(programming_language_name): return in_memory_datastore&#۹۱;programming_language_name] |
اپلیکیشن را اجرا کرده و به آدرس http://127.0.0.1:5000/programming_languages/COBOL بروید. شما باید خروجی مشابه زیر را ببینید:
۱ ۲ ۳ |
{"contribution":"record data","name":"COBOL","publication_year":۱۹۶۰} |
اضافه کردن فیلتر به اندپوینت List
دیکشنری in_memory_datastore در فایل prog_lang_app.py را با استفاده کد زیر بهروزرسانی کنید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۱۰ ۱۱ ۱۲ ۱۳ ۱۴ ۱۵ ۱۶ |
... in_memory_datastore = { "COBOL": {"name": "COBOL", "publication_year": ۱۹۶۰, "contribution": "record data"}, "ALGOL": {"name": "ALGOL", "publication_year": ۱۹۵۸, "contribution": "scoping and nested functions"}, "APL": {"name": "APL", "publication_year": ۱۹۶۲, "contribution": "array processing"}, "BASIC": {"name": "BASIC", "publication_year": ۱۹۶۴, "contribution": "runtime interpretation, office tooling"}, "PL": {"name": "PL", "publication_year": ۱۹۶۶, "contribution": "constants, function overloading, pointers"}, "SIMULA67": {"name": "SIMULA67", "publication_year": ۱۹۶۷, "contribution": "class/object split, subclassing, protected attributes"}, "Pascal": {"name": "Pascal", "publication_year": ۱۹۷۰, "contribution": "modern unary, binary, and assignment operator syntax expectations"}, "CLU": {"name": "CLU", "publication_year": ۱۹۷۵, "contribution": "iterators, abstract data types, generics, checked exceptions"}, } ... |
حالا شما میتوانید کدی را که به کلاینتها اجازه میدهد تا بر روی پارامتر publication_year فیلتر ایجاد کند، اضافه کنید:
۱ ۲ ۳ ۴ |
from flask import Flask, request app = Flask(__name__) ... |
باید فانکشن ()list_programming_languages را به شکل زیر تغییر دهید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۱۰ ۱۱ ۱۲ ۱۳ ۱۴ ۱۵ |
... @app.get('/programming_languages') def list_programming_languages(): before_year = request.args.get('before_year') or '۳۰۰۰۰' after_year = request.args.get('after_year') or '۰' qualifying_data = list( filter( lambda pl: int(before_year) > pl&#۹۱;'publication_year'] > int(after_year), in_memory_datastore.values() ) ) return {"programming_languages": qualifying_data} |
حالا کلاینتها میتوانند با استفاده از دو پارامتر before_year و after_year زبانهای برنامهنویسی را فیلتر کنند.
ساخت اندپوینت Create
تا به اینجای کار اندپوینتها برای درخواستهای GET نوشته شدهاند، اما اندپوینت Create منتظر درخواست POST میماند. بدنه این درخواست شمال تمام اطلاعات لازم برای ایجاد و اضافه کردن یک داده جدید است.
برای ساخت این اندپوینت، فایل prog_lang_app.py را به صورت زیر تغییر دهید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ |
... @app.route('/programming_languages', methods=&#۹۱;'GET', 'POST']) def programming_languages_route(): if request.method == 'GET': return list_programming_languages() elif request.method == "POST": return create_programming_language(request.get_json(force=True)) |
متد create_programming_language را زیر متد list_programming_languages اضافه کنید:
۱ ۲ ۳ ۴ ۵ ۶ |
... def create_programming_language(new_lang): language_name = new_lang&#۹۱;'name'] in_memory_datastore&#۹۱;language_name] = new_lang return new_lang |
حالا از دستور cURL برای ساخت یک زبان برنامهنویسی جدید استفاده کنید:
۱ ۲ ۳ ۴ ۵ |
curl -X POST http://۱۲۷.۰.۰.۱:۵۰۰۰/programming_languages -H 'Content-Type: application/json' -d '{"name": "Java", "publication_year": 1995, "contribution": "Object-oriented programming language."}' |
سپس با وارد کردن دستور زیر، یک درخواست GET ارسال کنید:
http://127.0.0.1:5000/programming_languages
۱ ۲ ۳ |
curl http://۱۲۷.۰.۰.۱:۵۰۰۰/programming_languages |
مشاهده میکنید که داده مربوط به زبان برنامهنویسی جاوا در قالب JSON ارسال میشود.
ساخت اندپوینت Update
دستور PUT برای بهروزرسانی داده استفاده میشود. برای ساخت این اندپیونت، در فایل prog_lang_app.py فانکشنهای app.route@ و ()get_programming_language را حذف و به جای آنها کد زیر را وارد کنید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ |
... @app.route('/programming_languages/<programming_language_name>', methods=&#۹۱;'GET', 'PUT']) def programming_language_route(programming_language_name): if request.method == 'GET': return get_programming_language(programming_language_name) elif request.method == "PUT": return update_programming_language(programming_language_name, request.get_json(force=True)) |
حالا فانکشن ()update_programming_language را زیر فانکشن ()get_programming_language وارد کنید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ |
... def update_programming_language(lang_name, new_lang_attributes): lang_getting_update = in_memory_datastore&#۹۱;lang_name] lang_getting_update.update(new_lang_attributes) return lang_getting_update |
برای تست اندپوینت جدید خودتان، یک درخواست بهروزرسانی را ارسال کنید:
۱ ۲ ۳ ۴ ۵ |
curl -X PUT http://۱۲۷.۰.۰.۱:۵۰۰۰/programming_languages/Java -H 'Content-Type: application/json' -d '{"contribution": "The JVM"}' |
حالا با ارسال یک درخواست GET به اندپوینت list، می توانید داده بهروزشده را ببینید:
۱ ۲ ۳ |
curl http://۱۲۷.۰.۰.۱:۵۰۰۰/programming_languages |
ساخت اندپوینت Delete
ساختار اندپوینت Delete مشابه اندپوینت Update است. برای اضافه کردن این اندپوینت، فایل prog_lang_app.py را به شکل زیر تغییر دهید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۱۰ ۱۱ |
... @app.route('/programming_languages/<programming_language_name>', methods=&#۹۱;'GET', 'PUT', 'DELETE']) def programming_language_route(programming_language_name): if request.method == 'GET': return get_programming_language(programming_language_name) elif request.method == "PUT": return update_programming_language(programming_language_name, request.get_json(force=True)) elif request.method == "DELETE": return delete_programming_language(programming_language_name) |
حالا فانکشن ()delete_programming_language را زیر فانکشن ()update_programming_language اضافه کنید:
۱ ۲ ۳ ۴ ۵ ۶ ۷ |
... def delete_programming_language(lang_name): deleting_lang = in_memory_datastore&#۹۱;lang_name] del in_memory_datastore&#۹۱;lang_name] return deleting_lang |
برای تست این اندپوینت، میتوانید درخواست زیر را ارسال کنید:
۱ ۲ ۳ |
curl -X DELETE http://۱۲۷.۰.۰.۱:۵۰۰۰/programming_languages/COBOL |
کد نهایی
در آخر فایل نهایی باید به شکل زیر باشد:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۱۰ ۱۱ ۱۲ ۱۳ ۱۴ ۱۵ ۱۶ ۱۷ ۱۸ ۱۹ ۲۰ ۲۱ ۲۲ ۲۳ ۲۴ ۲۵ ۲۶ ۲۷ ۲۸ ۲۹ ۳۰ ۳۱ ۳۲ ۳۳ ۳۴ ۳۵ ۳۶ ۳۷ ۳۸ ۳۹ ۴۰ ۴۱ ۴۲ ۴۳ ۴۴ ۴۵ ۴۶ ۴۷ ۴۸ ۴۹ ۵۰ ۵۱ ۵۲ ۵۳ ۵۴ ۵۵ ۵۶ ۵۷ ۵۸ ۵۹ ۶۰ ۶۱ ۶۲ ۶۳ ۶۴ ۶۵ |
from flask import Flask, request app = Flask(__name__) in_memory_datastore = { "COBOL": {"name": "COBOL", "publication_year": ۱۹۶۰, "contribution": "record data"}, "ALGOL": {"name": "ALGOL", "publication_year": ۱۹۵۸, "contribution": "scoping and nested functions"}, "APL": {"name": "APL", "publication_year": ۱۹۶۲, "contribution": "array processing"}, "BASIC": {"name": "BASIC", "publication_year": ۱۹۶۴, "contribution": "runtime interpretation, office tooling"}, "PL": {"name": "PL", "publication_year": ۱۹۶۶, "contribution": "constants, function overloading, pointers"}, "SIMULA67": {"name": "SIMULA67", "publication_year": ۱۹۶۷, "contribution": "class/object split, subclassing, protected attributes"}, "Pascal": {"name": "Pascal", "publication_year": ۱۹۷۰, "contribution": "modern unary, binary, and assignment operator syntax expectations"}, "CLU": {"name": "CLU", "publication_year": ۱۹۷۵, "contribution": "iterators, abstract data types, generics, checked exceptions"}, } @app.route('/programming_languages', methods=&#۹۱;'GET', 'POST']) def programming_languages_route(): if request.method == 'GET': return list_programming_languages() elif request.method == "POST": return create_programming_language(request.get_json(force=True)) def list_programming_languages(): before_year = request.args.get('before_year') or '۳۰۰۰۰' after_year = request.args.get('after_year') or '۰' qualifying_data = list( filter( lambda pl: int(before_year) > pl&#۹۱;'publication_year'] > int(after_year), in_memory_datastore.values() ) ) return {"programming_languages": qualifying_data} def create_programming_language(new_lang): language_name = new_lang&#۹۱;'name'] in_memory_datastore&#۹۱;language_name] = new_lang return new_lang @app.route('/programming_languages/<programming_language_name>', methods=&#۹۱;'GET', 'PUT', 'DELETE']) def programming_language_route(programming_language_name): if request.method == 'GET': return get_programming_language(programming_language_name) elif request.method == "PUT": return update_programming_language(programming_language_name, request.get_json(force=True)) elif request.method == "DELETE": return delete_programming_language(programming_language_name) def get_programming_language(programming_language_name): return in_memory_datastore&#۹۱;programming_language_name] def update_programming_language(lang_name, new_lang_attributes): lang_getting_update = in_memory_datastore&#۹۱;lang_name] lang_getting_update.update(new_lang_attributes) return lang_getting_update def delete_programming_language(lang_name): deleting_lang = in_memory_datastore&#۹۱;lang_name] del in_memory_datastore&#۹۱;lang_name] return deleting_lang |
اگر تمام درخواستهای شما با موفقیت ارسال شده و پاسخ آن را دریافت میکنید، تبریک میگوییم، شما موفق به ساخت API با Flask شدهاید.