دوال HTTP السحابية في بايثون

1. مقدمة

b158ce75c3cccd6d.png

Python هي لغة برمجة شائعة مفتوحة المصدر يستخدمها علماء البيانات ومطورو تطبيقات الويب ومسؤولو النظم وغيرهم.

Cloud Functions هي منصة حوسبة بدون خادم تعتمد على الأحداث. تسمح لك ميزة Cloud Functions بكتابة الرمز البرمجي بدون القلق بشأن توفير الموارد أو التطوير لتلبية المتطلبات المتغيّرة.

هناك نوعان من دوال السحابة:

  • تستجيب دوال HTTP لطلبات HTTP. ستنشئ اثنين في هذا الدرس التطبيقي حول الترميز.
  • يتم تفعيل وظائف الخلفية من خلال أحداث، مثلاً رسالة يتم نشرها على Cloud Pub/Sub أو ملف يتم تحميله إلى Cloud Storage. لم نتناول ذلك في هذا التمرين المعملي، ولكن يمكنك قراءة المزيد من خلال المستندات.

efb3268e3b74ed4f.png

سيساعدك هذا الدرس التطبيقي في إنشاء الدوال السحابية في بايثون.

ما الذي ستقوم ببنائه

في هذا الدرس التطبيقي حول الترميز، ستنشر دالة Cloud عند استدعائها عبر HTTP، حيث تعرض الرسالة "Python Powered" الشعار:

a7aaf656b78050fd.png

ما ستتعرَّف عليه

  • كيفية كتابة دالة HTTP في السحابة الإلكترونية.
  • كيفية كتابة دالة السحابة الإلكترونية HTTP التي تأخذ الوسيطات
  • كيفية اختبار دالة HTTP Cloud
  • كيفية تشغيل خادم HTTP محلي في Python لتجربة الدالة
  • كيفية كتابة دالة HTTP للسحابة الإلكترونية تؤدي إلى عرض صورة

2. الإعداد والمتطلبات

إعداد بيئة ذاتية

  1. سجِّل الدخول إلى Google Cloud Console وأنشئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي سلسلة أحرف لا تستخدمها Google APIs. ويمكنك تعديلها في أي وقت.
  • يكون رقم تعريف المشروع فريدًا في جميع مشاريع Google Cloud وغير قابل للتغيير (لا يمكن تغييره بعد تحديده). تنشئ Cloud Console سلسلة فريدة تلقائيًا. فعادةً لا تهتم بما هو. في معظم الدروس التطبيقية حول الترميز، يجب الإشارة إلى رقم تعريف المشروع (الذي يتم تحديده عادةً على أنّه PROJECT_ID). وإذا لم يعجبك رقم التعريف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. ويمكنك بدلاً من ذلك تجربة طلبك الخاص ومعرفة ما إذا كان متاحًا. ولا يمكن تغييره بعد هذه الخطوة ويبقى طوال مدة المشروع.
  • لمعلوماتك، هناك قيمة ثالثة، وهي رقم المشروع، الذي تستخدمه بعض واجهات برمجة التطبيقات. اطّلِع على مزيد من المعلومات حول هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام الموارد/واجهات برمجة التطبيقات في Cloud. لن يؤدي إكمال هذا الدرس التطبيقي حول الترميز إلى فرض أي تكاليف، إن وُجدت. لإيقاف تشغيل الموارد لتجنب تحمُّل الفواتير إلى ما هو أبعد من هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

بدء Cloud Shell

يمكنك إدارة Google Cloud عن بُعد من الكمبيوتر المحمول، إلا أنّك ستستخدم في هذا الدرس التطبيقي Cloud Shell، وهي بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

تفعيل Cloud Shell

  1. من Cloud Console، انقر على تفعيل Cloud Shell 853e55310c205094.png.

3c1dabeca90e44e5.png

إذا كانت هذه هي المرة الأولى التي تبدأ فيها Cloud Shell، ستظهر لك شاشة وسيطة تصف ماهيتها. إذا ظهرت لك شاشة وسيطة، انقر على متابعة.

9c92662c6a846a5c.png

من المفترَض أن تستغرق عملية إدارة الحسابات والاتصال بخدمة Cloud Shell بضع دقائق فقط.

9f0e51b578fecce5.png

يتم تحميل هذا الجهاز الافتراضي مع جميع أدوات التطوير اللازمة. وتوفّر هذه الشبكة دليلاً رئيسيًا دائمًا بسعة 5 غيغابايت ويتم تشغيله في Google Cloud، ما يحسّن بشكل كبير من أداء الشبكة والمصادقة. يمكنك تنفيذ معظم عملك، إن لم يكن كلّه، في هذا الدرس التطبيقي حول الترميز باستخدام متصفّح.

بعد الربط بخدمة 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 APIs

شغِّل الأمر التالي من Cloud Shell للتأكّد من تفعيل Cloud Functions وCloud Build APIs:

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

3- إضافة دوال HTTP في السحابة الإلكترونية

تتم كتابة دوال HTTP السحابية في لغة بايثون كدوال بايثون عادية. يجب أن تقبل الدالة وسيطة 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" بعد ضبط الدليل المصدر كمساحة عمل:

cloudshell open-workspace .

لننشر هذه الدالة كدالة HTTP Cloud باستخدام الأمر 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: تحدد هذه السياسة بيئة التشغيل الخاصة باللغة. بالنسبة إلى بايثون، يمكن أن تكون هذه القيم حاليًا python37 أو python38 أو python39 أو python310 أو python312. راجِع بيئات التشغيل.
  • --trigger-http: سيتم تعيين نقطة نهاية للدالة. ستؤدي طلبات HTTP (POST وPUT وGET وDELETE وOPTIONS) إلى نقطة النهاية إلى تشغيل تنفيذ الدالة.
  • --allow-unauthenticated: ستكون الوظيفة متاحة للجميع، ما يسمح لجميع المتصلين بدون التحقّق من المصادقة.
  • لمزيد من المعلومات، يمكنك الاطّلاع على مقالة نشر دوال gcloud.

لاختبار الدالة، يمكنك النقر على عنوان URL httpsTrigger.url المعروض في ناتج الأمر أعلاه. يمكنك أيضًا استرداد عنوان URL آليًا واستدعاء الدالة باستخدام الأوامر التالية:

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

من المفترض أن تحصل على النتيجة التالية:

Hello World! 👋

4. كتابة دالة السحابة الإلكترونية HTTP التي تأخذ الوسيطات

تكون الدوال أكثر تنوّعًا عند قبول الوسيطات. لنحدِّد دالة جديدة 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
...

لاختبار الدالة، يمكنك النقر على عنوان URL httpsTrigger.url المعروض في ناتج الأمر أعلاه. يمكنك أيضًا استرداد عنوان URL آليًا واستدعاء الدالة باستخدام الأوامر التالية:

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

من المفترض أن تحصل على النتيجة التلقائية:

Hello World! 🚀

أنت تحصل على النتيجة التلقائية لأنّه لم يتم ضبط الوسيطة name. إضافة مَعلمة إلى عنوان URL:

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

هذه المرة، ستحصل على ردك المخصص:

Hello YOUR NAME! 🚀

الخطوة التالية هي إضافة اختبارات الوحدة لضمان استمرار عمل الوظائف على النحو المنشود عند تحديث رمز المصدر.

5- كتابة الاختبارات

يتم اختبار دوال HTTP السحابية في لغة بايثون باستخدام وحدة unittest من المكتبة العادية. ليست هناك حاجة إلى تشغيل محاكي أو محاكاة أخرى لاختبار الدالة — كل ما عليك هو رمز بايثون عادي.

في ما يلي شكل الاختبار للدالتَين 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. تُكتب اختبارات بايثون بالطريقة نفسها التي تُكتب بها ملفات بايثون الأخرى. فهي تبدأ بمجموعة من عمليات الاستيراد، ثم تحدد الفئات والدوال.
  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" الشعار.

6- أو كتابة "مستند Python" دالة HTTP السحابية

لنجعل إحدى الدوال الجديدة أكثر تسلية إلى حدٍ ما من خلال عرض "البيانات المستندة إلى بايثون" صورة لكل طلب:

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
...

لاختبار الدالة، انقر على عنوان URL httpsTrigger.url المعروض في ناتج الأمر أعلاه. إذا كان كل شيء يعمل بشكل صحيح، ستظهر لك الرسالة "واجهة Python" شعار في علامة تبويب جديدة داخل المتصفح

بعد ذلك، ستنشئ تطبيقًا لتتمكّن من تشغيل الدالة وتجربتها محليًا قبل النشر.

7. تشغيل الدالة محليًا

يمكنك تشغيل دالة HTTP محليًا عن طريق إنشاء تطبيق ويب واستدعاء الدالة في مسار ما. يمكنك إضافته في نفس الدليل الموجود في الدالة. يتضمّن الملف المُسمّى 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. ويسجِّل مسارًا في عنوان URL الأساسي الذي يتم التعامل معه مع دالة تُسمى index().
  3. بعد ذلك، تستدعي الدالة index() الدالة python_powered، وتمررها الطلب الحالي.

تأكَّد من تثبيت إطار عمل Flask في بيئة التطوير:

pip install flask

يؤدي تثبيت Flask إلى ظهور نتيجة مشابهة لما يلي:

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

لتشغيل هذا التطبيق محليًا، شغِّل الأمر التالي:

python web_app.py

يمكنك الآن استخدام Cloud Shell Web Preview لاختبار تطبيق الويب في المتصفّح. في Cloud Shell، انقر على "معاينة الويب" وحدد "معاينة على المنفذ 8080":

6c9ff9e5c692c58e.gif

تفتح Cloud Shell عنوان URL للمعاينة على خدمة الخادم الوكيل في نافذة متصفِّح جديدة. تحصر معاينة الويب الدخول عبر HTTPS في حساب المستخدم فقط. إذا كان كل شيء يعمل بشكل صحيح، ينبغي أن ترى "واجهة Python" الشعار!

8e5c3ead11cfd103.png

8. تهانينا!

b158ce75c3cccd6d.png

لقد فعّلت دوال HTTP Cloud باستخدام وظائف اصطلاحية تعالج طلبات الويب من خلال إطار العمل Flask.

يستند أسعار Cloud Functions إلى عدد مرات استدعاء الدالة، بما في ذلك طبقة مجانية للدوال التي لا يتم تشغيلها كثيرًا. بعد الانتهاء من اختبار دوال Cloud، يمكنك حذفها باستخدام gcloud:

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

يمكنك أيضًا حذف الوظائف من وحدة تحكُّم Google Cloud.

نأمل أن تستمتع باستخدام دوال Cloud في بايثون.