توابع ابری اچ‌تی‌تی‌پی در Python

۱. مقدمه

b158ce75c3cccd6d.png

Python یک زبان برنامه‌نویسی متن‌باز محبوب است که توسط متخصصان علم داده، توسعه‌دهندگان برنامه وب، سرپرستان سامانه، و غیره استفاده می‌شود.

Cloud Functions یک پلاتفرم محاسباتی بدون سرور رویدادمحور است. Cloud Functions به شما امکان می‌دهد بدون نگرانی درباره تأمین منابع یا مقیاس‌بندی برای رسیدگی به الزامات درحال تغییر، کد خود را بنویسید.

دو نوع Cloud Functions وجود دارد:

  • توابع اچ‌تی‌تی‌پی به درخواست‌های اچ‌تی‌تی‌پی پاسخ می‌دهند. در این codelab چند مورد خواهید ساخت.
  • توابع پس‌زمینه با رویدادهایی مثل انتشار پیام در Cloud Pub/Sub یا بارگذاری فایل در فضای ذخیره‌سازی ابری راه‌اندازی می‌شوند. در این آزمایشگاه به این موضوع نمی‌پردازیم، اما می‌توانید در اسناد اطلاعات بیشتری کسب کنید.

efb3268e3b74ed4f.png

این codelab شما را در ایجاد کردن Cloud Functions خودتان در Python راهنمایی می‌کند.

آنچه خواهید ساخت

در این codelab، یک «تابع ابری» منتشر خواهید کرد که وقتی ازطریق HTTP فراخوانی می‌شود، نشان‌واره «Python Powered» را نمایش می‌دهد:

a7aaf656b78050fd.png

آنچه خواهید آموخت

  • نحوه نوشتن تابع ابری اچ‌تی‌تی‌پی.
  • نحوه نوشتن تابع ابری اچ‌تی‌تی‌پی که متغیر مستقل می‌گیرد.
  • نحوه آزمایش کردن تابع ابری اچ‌تی‌تی‌پی.
  • نحوه اجرای سرور محلی Python HTTP برای امتحان کردن تابع.
  • نحوه نوشتن تابع ابری اچ‌تی‌تی‌پی که تصویری را برمی‌گرداند.

۲. راه‌اندازی و الزامات

راه‌اندازی محیط با سرعت شخص

  1. به سیستم کنسول Google Cloud وارد شوید و پروژه جدیدی ایجاد کنید یا از پروژه موجودی دوباره استفاده کنید. اگر ازقبل حساب Gmail یا Google Workspace ندارید، باید حسابی ایجاد کنید.

fbef9caa1602edd0.pnga99b7ace416376c4.png5e3ff691252acf41.png

  • نام پروژه نام نمایشی برای شرکت‌کنندگان این پروژه است. این رشته نویسه‌ای است که Google APIs از آن استفاده نمی‌کند. همیشه می‌توانید آن را به‌روز کنید.
  • شناسه پروژه در همه پروژه‌های Google Cloud یکتا است و تغییرناپذیر است (پس‌از تنظیم شدن نمی‌توان آن را تغییر داد). Cloud Console به‌طور خودکار یک رشته یکتا تولید می‌کند؛ معمولاً برایتان مهم نیست که این رشته چیست. در اکثر codelabها، باید به «شناسه پروژه» خود (که معمولاً به‌عنوان PROJECT_ID شناسایی می‌شود) ارجاع دهید. اگر شناسه تولیدشده را دوست ندارید، می‌توانید شناسه تصادفی دیگری تولید کنید. یا می‌توانید نام کاربری خودتان را امتحان کنید و ببینید دردسترس است یا نه. بعداز این مرحله نمی‌توان آن را تغییر داد و در طول پروژه باقی می‌ماند.
  • برای اطلاع شما، مقدار سومی هم وجود دارد، شماره پروژه، که برخی‌از میاناهای برنامه‌سازی کاربردی از آن استفاده می‌کنند. در اسناد درباره هر سه این مقادیر بیشتر بدانید.
  1. سپس، برای استفاده از منابع/ میاناهای برنامه‌سازی کاربردی Cloud، باید صورت‌حساب را در Cloud Console فعال کنید. اجرای این codelab هزینه زیادی نخواهد داشت، اگر اصلاً هزینه‌ای داشته باشد. برای خاموش کردن منابع به‌منظور جلوگیری از ایجاد صورت‌حساب فراتر از این آموزش، می‌توانید منابعی را که ایجاد کرده‌اید حذف کنید یا پروژه را حذف کنید. کاربران جدید Google Cloud واجدشرایط برنامه دوره آزمایشی رایگان ۳۰۰ دلاری هستند.

شروع Cloud Shell

درحالی‌که Google Cloud را می‌توان از راه دور از رایانه کیفی شما اجرا کرد، در این codelab از Cloud Shell استفاده خواهید کرد که یک محیط خط فرمان است که در Cloud اجرا می‌شود.

فعال کردن Cloud Shell

  1. از Cloud Console، روی فعال کردن Cloud Shell 853e55310c205094.png کلیک کنید.

3c1dabeca90e44e5.png

اگر این اولین‌باری است که Cloud Shell را راه‌اندازی می‌کنید، صفحه‌ای واسط به شما نشان داده می‌شود که توضیح می‌دهد Cloud Shell چیست. اگر صفحه واسط به شما نشان داده شد، روی ادامه کلیک کنید.

9c92662c6a846a5c.png

تأمین و اتصال به Cloud Shell فقط چند لحظه طول می‌کشد.

9f0e51b578fecce5.png

این ماشین مجازی با همه ابزارهای توسعه موردنیاز بار شده است. این ابزار یک دایرکتوری خانگی دائمی ۵ گیگابایتی ارائه می‌دهد و در Google Cloud اجرا می‌شود، که عملکرد شبکه و اصالت‌سنجی را به‌طور قابل‌توجهی بهبود می‌بخشد. بخش زیادی از کارتان در این codelab، اگر نگوییم همه آن، می‌تواند با مرورگر انجام شود.

پس‌از اتصال به Cloud Shell، باید ببینید که اصالت‌سنجی شده‌اید و پروژه روی شناسه پروژه شما تنظیم شده است.

  1. فرمان زیر را در Cloud Shell اجرا کنید تا تأیید شود که اصالت‌سنجی شده‌اید:
gcloud auth list

خروجی فرمان

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. فرمان زیر را در Cloud Shell اجرا کنید تا مطمئن شوید فرمان gcloud پروژه شما را می‌شناسد:
gcloud config list project

خروجی فرمان

[core]
project = <PROJECT_ID>

اگر این‌طور نیست، می‌توانید آن را با این فرمان تنظیم کنید:

gcloud config set project <PROJECT_ID>

خروجی فرمان

Updated property [core/project].

مطمئن شوید Cloud Functions و Cloud Build API فعال باشند

فرمان زیر را از Cloud Shell اجرا کنید تا مطمئن شوید Cloud Functions و Cloud Build API فعال هستند:

gcloud services enable \
  cloudfunctions.googleapis.com \
  cloudbuild.googleapis.com

توجه: Cloud Build با فرمان gcloud functions deploy فراخوانی می‌شود و به‌طور خودکار کد شما را در تصویر کانتینر می‌سازد.

بارگیری کد منبع

از پایانه Cloud Shell، فرمان‌های زیر را اجرا کنید:

REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="cloud-functions-python-http"

git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL
cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR

محتوای دایرکتوری منبع را بررسی کنید:

ls

باید فایل‌های زیر را داشته باشید:

main.py  python-powered.png  test_main.py  web_app.py

۳. معرفی توابع ابری اچ‌تی‌تی‌پی

توابع ابری اچ‌تی‌تی‌پی در Python به‌عنوان توابع معمولی Python نوشته می‌شوند. تابع باید یک متغیر مستقل flask.Request را بپذیرد که معمولاً request نامیده می‌شود.

main.py

import flask


def hello_world(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello World! 👋"
    """
    response = "Hello World! 👋"

    return flask.Response(response, mimetype="text/plain")

# ...

می‌توانید فایل را با ویرایشگر خط فرمان دلخواهتان (nano،‏ vim، یا emacs) باز کنید. همچنین می‌توانید پس‌از تنظیم دایرکتوری منبع به‌عنوان فضای کاری، آن را در Cloud Shell Editor باز کنید:

cloudshell open-workspace .

بیایید این تابع را به‌عنوان یک تابع ابری اچ‌تی‌تی‌پی بااستفاده از فرمان gcloud functions deploy پیاده‌سازی کنیم:

FUNCTION_NAME="hello_world"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

برونداد فرمان:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

یادداشت‌هایی درباره گزینه‌های gcloud functions deploy:

  • ‫--runtime: این گزینه زمان اجرای زبان را مشخص می‌کند. برای Python، این مقدار درحال‌حاضر می‌تواند python37،‏ python38،‏ python39،‏ python310، یا python312 باشد. زمان‌های اجرا را ببینید.
  • ‫--trigger-http: نقطه پایانی به تابع اختصاص داده خواهد شد. درخواست‌های HTTP (POST،‏ PUT،‏ GET،‏ DELETE، و OPTIONS) به نقطه پایانی، اجرای تابع را راه‌اندازی می‌کند.
  • --allow-unauthenticated: این تابع عمومی خواهد بود و به همه تماس‌گیرندگان اجازه می‌دهد بدون بررسی اصالت‌سنجی دسترسی داشته باشند.
  • برای اطلاعات بیشتر، gcloud functions deploy را ببینید.

برای آزمایش کردن تابع، می‌توانید روی نشانی وب httpsTrigger.url نمایش‌داده‌شده در خروجی فرمان بالا کلیک کنید. همچنین می‌توانید نشانی وب را به‌صورت برنامه‌نویسی بازیابی کنید و تابع را با فرمان‌های زیر فراخوانی کنید:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

باید نتیجه زیر را دریافت کنید:

Hello World! 👋

۴. نوشتن تابع ابری اچ‌تی‌تی‌پی که آرگومان می‌گیرد

توابع وقتی متغیرهای مستقل را می‌پذیرند، کاربردهای بیشتری دارند. بیایید تابع جدید hello_name را تعریف کنیم که از پارامتر name پشتیبانی می‌کند:

main.py

# ...

def hello_name(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello {NAME}! 🚀" if "name=NAME" is defined in the GET request
    - "Hello World! 🚀" otherwise
    """
    name = request.args.get("name", "World")
    response = f"Hello {name}! 🚀"

    return flask.Response(response, mimetype="text/plain")

# ...

بیایید این تابع جدید را مستقر کنیم:

FUNCTION_NAME="hello_name"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

برونداد فرمان:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

برای آزمایش کردن تابع، می‌توانید روی نشانی وب httpsTrigger.url نمایش‌داده‌شده در خروجی فرمان بالا کلیک کنید. همچنین می‌توانید نشانی وب را به‌صورت برنامه‌نویسی بازیابی کنید و تابع را با فرمان‌های زیر فراخوانی کنید:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

باید نتیجه پیش‌فرض را دریافت کنید:

Hello World! 🚀

نتیجه پیش‌فرض را دریافت می‌کنید زیرا آرگومان name تنظیم نشده است. پارامتری به نشانی وب اضافه کنید:

curl -w "\n" $URL?name=YOUR%20NAME

این بار، پاسخ سفارشی‌تان را دریافت خواهید کرد:

Hello YOUR NAME! 🚀

مرحله بعدی افزودن آزمون‌های واحد است تا مطمئن شوید که توابع شما هنگام به‌روزرسانی کد منبع همچنان طبق انتظار کار می‌کنند.

۵. نوشتن آزمایش‌ها

توابع ابری اچ‌تی‌تی‌پی در Python بااستفاده از پودمان unittest از کتابخانه استاندارد آزمایش می‌شوند. برای آزمایش کردن تابع خود نیازی به اجرای شبیه‌ساز یا شبیه‌سازی‌های دیگر نیست—فقط کد Python معمولی.

در اینجا مثالی از آزمایش برای توابع hello_world و hello_name آورده شده است:

test_main.py

import unittest
import unittest.mock

import main


class TestHello(unittest.TestCase):
    def test_hello_world(self):
        request = unittest.mock.Mock()

        response = main.hello_world(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 👋"

    def test_hello_name_no_name(self):
        request = unittest.mock.Mock(args={})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 🚀"

    def test_hello_name_with_name(self):
        name = "FirstName LastName"
        request = unittest.mock.Mock(args={"name": name})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == f"Hello {name}! 🚀"
  1. آزمایش‌های Python به همان روشی نوشته می‌شوند که سایر فایل‌های Python نوشته می‌شوند. این فایل‌ها با مجموعه‌ای از واردات شروع می‌شوند، سپس کلاس‌ها و توابع را تعریف می‌کنند.
  2. اظهارنامه آزمایشی به‌صورت class TestHello(TestCase) است. باید کلاسی باشد که از unittest.TestCase ارث‌بری می‌کند.
  3. کلاس آزمایشی دارای روش‌هایی است که هرکدام باید با test_ شروع شوند و نشان‌دهنده چارچوب‌های تست جداگانه هستند.
  4. هر چارچوب تست یکی از توابع ما را با شبیه‌سازی پارامتر request (یعنی جایگزین کردن آن با یک شیء جعلی با داده‌های خاص موردنیاز برای تست) آزمایش می‌کند.
  5. پس‌از فراخوانی هر تابع، آزمایش پاسخ‌های HTTP را بررسی می‌کند تا مطمئن شود همان چیزی است که انتظار داشتیم.

ازآنجایی‌که main.py به flask وابسته است، مطمئن شوید چارچوب Flask در محیط آزمایشی شما نصب شده باشد:

pip install flask

نصب Flask نتیجه‌ای مشابه زیر را نشان می‌دهد:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

این آزمایش‌ها را به‌صورت محلی اجرا کنید:

python -m unittest

سه آزمایش واحد باید موفقیت‌آمیز باشد:

...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

سپس، تابع جدیدی ایجاد می‌کنید که نشان‌واره «Python Powered» را برمی‌گرداند.

‫۶. نوشتن تابع ابری اچ‌تی‌تی‌پی «با پشتیبانی Python»

بیایید با برگرداندن تصویر «Python Powered» برای هر درخواست، تابع جدید را کمی سرگرم‌کننده‌تر کنیم:

a7aaf656b78050fd.png

فهرست زیر کد لازم برای انجام این کار را نشان می‌دهد:

main.py

# ...

def python_powered(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - The official "Python Powered" logo
    """
    return flask.send_file("python-powered.png")

استقرار تابع python_powered جدید:

FUNCTION_NAME="python_powered"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

برونداد فرمان:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

برای آزمایش کردن تابع، روی نشانی وب httpsTrigger.url نمایش‌داده‌شده در خروجی فرمان بالا کلیک کنید. اگر همه چیز به‌درستی کار کند، نشان‌واره «Python Powered» را در برگه جدید مرورگر خواهید دید!

سپس، برنامه‌ای ایجاد خواهید کرد تا بتوانید تابع خود را قبل‌از استقرار به‌صورت محلی اجرا و امتحان کنید.

‫۷. درحال اجرای تابع به‌صورت محلی

می‌توانید با ایجاد کردن برنامه وب و فراخوانی تابع در یک مسیر، تابع اچ‌تی‌تی‌پی را به‌صورت محلی اجرا کنید. می‌توانید آن را در همان پوشه تابع خود اضافه کنید. فایل با نام web_app.py حاوی محتوای زیر است:

web_app.py

import flask

import main

app = flask.Flask(__name__)


@app.get("/")
def index():
    return main.python_powered(flask.request)


if __name__ == "__main__":
    # Local development only
    # Run "python web_app.py" and open http://localhost:8080
    app.run(host="localhost", port=8080, debug=True)
  1. این فایل یک برنامه Flask ایجاد می‌کند.
  2. این کد مسیری را در نشانی وب پایه ثبت می‌کند که با تابعی به‌نام index() مدیریت می‌شود.
  3. سپس تابع index() تابع python_powered ما را فراخوانی می‌کند و درخواست فعلی را به آن ارسال می‌کند.

مطمئن شوید چارچوب Flask در محیط توسعه نرم‌افزار شما نصب شده باشد:

pip install flask

نصب Flask نتیجه‌ای مشابه زیر را نشان می‌دهد:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

برای اجرای این برنامه به‌صورت محلی، فرمان زیر را اجرا کنید:

python web_app.py

اکنون از «پیش‌نمایش وب Cloud Shell» برای آزمایش برنامه وب در مرورگرتان استفاده کنید. در Cloud Shell، روی دکمه «پیش‌نمایش وب» کلیک کنید و «پیش‌نمایش در درگاه ۸۰۸۰» را انتخاب کنید:

6c9ff9e5c692c58e.gif

Cloud Shell نشانی وب پیش‌نمایش را در سرویس پیشکار خود در پنجره مرورگر جدیدی باز می‌کند. پیش‌نمایش وب دسترسی ازطریق HTTPS را فقط به حساب کاربری شما محدود می‌کند. اگر همه‌چیز به‌درستی کار می‌کند، باید نشان‌واره «Python Powered» را ببینید!

8e5c3ead11cfd103.png

‫۸. تبریک!

b158ce75c3cccd6d.png

شما HTTP Cloud Functions را بااستفاده از توابع اصطلاحی که درخواست‌های وب را با چارچوب Flask مدیریت می‌کنند، مستقر کرده‌اید.

قیمت‌گذاری Cloud Functions براساس تعداد دفعات فراخوانی تابع شما است، ازجمله سطح رایگان برای توابعی که اغلب اجرا نمی‌شوند. پس‌از اتمام آزمایش Cloud Functions، می‌توانید آن‌ها را بااستفاده از gcloud حذف کنید:

gcloud functions delete hello_world --quiet
gcloud functions delete hello_name --quiet
gcloud functions delete python_powered --quiet

همچنین می‌توانید توابع را از کنسول Google Cloud حذف کنید.

امیدواریم از استفاده از Cloud Functions در Python لذت ببرید!