كيفية بناء عنوان URL لـ Serverless باستخدام AWS Lambda و S3

باستخدام الرسومات من SAP Scenes Pack

خلال هذا المنشور ، سنقوم بإنشاء مُختصر URL بدون خادم باستخدام Amazon Web Services (AWS) Lambda و S3. على الرغم من أنك لا تحتاج إلى أي خبرة سابقة مع AWS ، إلا أنني أفترض بعض الإلمام بـ JavaScript ES6 و Node.js.

من عجيب المفارقات أن عناوين URL التي سيتم إنشاؤها من أداة تقصير عناوين URL الخاصة بنا غالباً ما تكون أطول من عناوين URL التي يعيدون توجيهها إليها - وذلك لأننا نستخدم عنوان موقع الويب الافتراضي لمجموعة S3. قرب نهاية المنشور ، سأناقش كيف يمكنك إضافة مجال مخصص للتغلب على هذا القيد.

عرض التجريبي

انظر الكود على جيثب

من السهل نسبيًا البدء بـ AWS ومع ذلك ، هناك بالتأكيد تعقيد متصور. يمكن أن يكون عدد الخدمات المتاحة شاقًا للاختيار من بينها تداخل العديد منها في الوظائف. وحدة التحكم AWS البطيئة وغير البديهية لا تساعد ، ولا الوثائق النصية الثقيلة على الإنترنت. لكن خلال هذا المنشور ، آمل أن أثبت أن أفضل طريقة لتبني خدمات AWS هي استخدام نهج تدريجي ويمكنك البدء باستخدام عدد قليل فقط من الخدمات.

سنستخدم Serverless Framework للتفاعل مع AWS وبالتالي لن تكون هناك حاجة لتسجيل الدخول إلى AWS Management Console. يوفر إطار Serverless لوحة تجريدية على AWS ويساعد في توفير بنية المشروع وافتراضات التكوين المعقولة. إذا كنت تريد معرفة المزيد قبل البدء ، فيجب عليك قراءة مستنداتهم.

هندسة معمارية

قبل القفز إلى أي تطور ، دعونا أولاً نلقي نظرة على خدمات AWS التي سنستخدمها لبناء اختصار عنوان URL الخاص بنا.

لاستضافة موقعنا ، سنستخدم خدمة تخزين ملفات Amazon S3. سنقوم بتكوين مجموعة S3 الخاصة بنا ، والتي يمكن اعتبارها بمثابة مجلد من المستوى الأعلى ، لخدمة موقع ويب ثابت. سيتألف الموقع من محتوى ثابت ونصوص من جانب العميل. ليست هناك إمكانية لتنفيذ التعليمات البرمجية من جانب الخادم (مثل PHP أو Ruby أو Java على سبيل المثال) ، ولكن هذا جيد بالنسبة لحالة الاستخدام الخاصة بنا.

سنستخدم أيضًا ميزة غير معروفة في S3 تتيح لك إعداد إعادة توجيه الكائنات الموجودة في مجموعات S3 ببساطة عن طريق إضافة قيمة الموقع - Redirect-Location إلى بيانات تعريف الكائن. سيؤدي تعيين هذا إلى عنوان URL إلى إعادة توجيه المتصفحات من خلال استجابة HTTP 301 ورأس الموقع.

يتكون عنوان URL الخاص بكائن S3 من عنوان المجموعة S3 متبوعًا باسم الكائن.

HTTP: // [دلو اسم] .s3-الموقع بين الاتحاد الأوروبي والغرب و1.amazonaws.com / [كائن اسم]

فيما يلي مثال لتنسيق كائن مجموعة S3 للمنطقة eu-west-1.

http://serverless-url-shortener.s3-website-eu-west-1.amazonaws.com/6GpLcdl

يصبح اسم الكائن "6GpLcdl" في نهاية عنوان URL في المثال أعلاه رمزًا قصيرًا لعناوين URL المختصرة الخاصة بنا. باستخدام هذه الوظيفة ، نحصل على إعادة توجيه عنوان URL الأصلي بالإضافة إلى إمكانات التخزين. لا نحتاج إلى قاعدة بيانات لتخزين تفاصيل أي رمز قصير يشير إلى عنوان URL حيث سيتم تخزين هذه المعلومات بدلاً من ذلك مع الكائن نفسه.

سننشئ وظيفة Lambda لحفظ هذه الكائنات S3 مع البيانات التعريفية المناسبة إلى دلو S3 الخاص بنا.

يمكنك بدلاً من ذلك استخدام جانب العميل AWS SDK في المستعرض لحفظ الكائنات. لكن من الأفضل استخراج هذه الوظيفة في خدمة منفصلة. يوفر ميزة عدم الحاجة إلى القلق بشأن كشف بيانات اعتماد الأمان وهو أكثر قابلية للتمديد في المستقبل. سنقوم بتعيين وظيفة Lambda إلى نقطة نهاية على بوابة API بحيث يمكن الوصول إليها من خلال مكالمة API.

ابدء

توجه إلى مستندات Serverless Framework واستعرض دليل البدء السريع. كجزء من عملية الإعداد ، يجب عليك تثبيت AWS CLI وتكوين بيانات اعتماد AWS الخاصة بك.

ابدأ بإنشاء ملف package.json في جذر المشروع.

{
  "name": "serverless-url-shortener" ،
  "البرامج النصية": {} ،
  "التبعيات": {}
}

نحن نعلم أننا سنحتاج إلى استخدام AWS SDK ، لذا تابع وتثبيته من NPM الآن عن طريق إدخال الأمر التالي.

npm تثبيت aws-sdk - حفظ

الآن قم بإنشاء ملف config.json أيضًا في جذر المشروع. سنستخدم هذا لتخزين خيارات المستخدم القابلة للتخصيص بتنسيق JSON.

أضف المفاتيح التالية مع القيم المناسبة للإعداد الخاص بك.

  • BUCKET - الاسم الذي تريد استخدامه لجرافة S3 الخاصة بك. سيصبح هذا جزءًا من عنوان URL القصير إذا اخترت عدم إضافة مجال مخصص. يجب أن تكون فريدة من نوعها في المنطقة التي تنشرها حتى لا تختار شيئًا عامًا جدًا. ولكن لا تقلق ، إذا كان اسم الجرافة الذي اخترته قيد الاستخدام بالفعل ، فسيتم تحذيرك من خلال خادم CLI Serverless عند النشر.
  • المنطقة - منطقة AWS التي ترغب في نشرها في. من الأفضل اختيار المنطقة الأقرب إلى المستخدمين لأسباب تتعلق بالأداء. إذا كنت تتابع فقط مع البرنامج التعليمي ، فسأستخدم eu-west-1.
  • المرحلة - المرحلة لنشر ل. عادةً ما يكون لديك بيئة مرحلية تنسخ نفس التكوين مثل بيئة الإنتاج الخاصة بك. يسمح لك هذا باختبار إصدارات البرامج بطريقة غير مدمرة. نظرًا لأن هذا برنامج تعليمي ، فسوف يتم نشره في مرحلة التطوير.

يجب أن يبدو ملف config.json مشابهاً لما يلي بمجرد اكتماله.

{
  "باكيت": "اسم دلو" ،
  "المنطقة": "eu-west-1" ،
  "المرحلة": "ديف" ،
}

بعد ذلك ، قم بإنشاء ملف آخر في جذر المشروع ، serverless.yml. سيؤدي هذا إلى الاحتفاظ بتكوين Framework Serverless الخاص بنا بتنسيق لغة ترميز YAML.

داخل هذا الملف ، سنبدأ بتحديد بيئتنا. لاحظ كيف يمكننا الرجوع إلى المتغيرات المخزنة في وقت سابق في config.json.

الخدمة: serverless-url-shortener

مزود:
  الاسم: أوس
  وقت التشغيل: nodejs6.10
  المرحلة: $ {file (config.json): STAGE}
  المنطقة: $ {file (config.json): REGION}
  iamRoleStatements:
    - التأثير: اسمح
      عمل:
        - s3: PutObject
      المصدر: "arn: aws: s3 ::: $ {file (config.json): BUCKET} / *"

يشير قسم iamRoleStatements إلى إدارة الهوية والوصول التي يتم استخدامها لإعداد أذونات Lambda. هنا نوفر Lambda حق الوصول إلى دلو S3 الخاص بنا.

لحفظ الكائنات ، نحتاج إلى إذن لتنفيذ s3: إجراء PutObject. يمكن إضافة أذونات أخرى هنا إذا كانت مطلوبة من قبل المشروع الخاص بك. ارجع إلى مستندات S3 للتعرف على الإجراءات الأخرى المتاحة.

يتم تعيين قيمة المورد على Amazon Resource Name لمجموعة S3 ، والذي يُستخدم لتحديد مورد AWS فريد. يعتمد تنسيق هذا المعرف على خدمة AWS التي تتم الإشارة إليها ، ولكن بشكل عام يكون لديها التنسيق التالي.

ARN: التقسيم: الخدمة: المنطقة: حساب معرف: الموارد

تحت مزود إلحاق تكوين وظائفنا.

المهام:
  متجر:
    معالج: api.handle
    الأحداث:
      - http:
          المسار: /
          الطريقة: آخر
          كور: صحيح

نحدد هنا تهيئة واجهة برمجة التطبيقات ونعيّن خريطة Lambda الخاصة بنا إلى حدث HTTP POST على عنوان URL الأساسي لـ API. يشير المعالج ذو القيمة api.handle إلى دالة باسم التعامل التي يتم تصديرها من api.js (لا نحتاج إلى ملحق ملف js لأننا في وقت سابق في serverless.yml قمنا بتعيين وقت التشغيل على nodejs6.10).

تستند Lambda إلى الحدث وبالتالي يتم تنفيذ الوظائف فقط بناءً على مشغلات محددة مسبقًا. لقد حددنا هنا حدث HTTP ولكن قد يكون هذا أيضًا حدث تم تشغيله بواسطة جدول DynamoDB أو قائمة انتظار SQS.

بعد ذلك في serverless.yml نحدد موارد AWS التي سيتم إنشاء مثيل لها بالنسبة لنا عند النشر باستخدام CloudFormation. تجدر الإشارة إلى أنه ليس عليك بالضرورة إعداد الموارد بهذه الطريقة ، يمكنك أيضًا إنشاؤها باستخدام AWS Management Console. توفير أذونات الوصول الصحيحة في مكانها ، لا يهم كيف يتم إنشاء الموارد. ولكن عند تعريف الخدمات المطلوبة في serverless.yml ، فأنت تحدد "البنية التحتية الخاصة بك كرمز" وتحصل على عدد من الفوائد عند القيام بذلك.

"البنية التحتية ككود هي الطريقة التي تحدد البنية التحتية للحوسبة والشبكة من خلال شفرة المصدر والتي يمكن معالجتها مثل أي نظام برمجي. يمكن الاحتفاظ بهذه التعليمة البرمجية في التحكم بالمصادر للسماح بالتدقيق و ReproducibleBuilds ، وتخضع لممارسات الاختبار والانضباط الكامل للتواصل المستمر. "
- مارتن فاولر

المضي قدما وإضافة تكوين الموارد.

مصادر:
  مصادر:
    ServerlessRedirectS3Bucket:
      النوع: AWS :: S3 :: دلو
      الخصائص:
        اسم BucketName: $ {file (config.json): BUCKET}
        AccessControl: PublicRead
        WebsiteConfiguration:
          IndexDocument: index.html
    ServerlessRedirectS3BucketPolicy:
      النوع: AWS :: S3 :: BucketPolicy
      الخصائص:
        المجموعة: $ {file (config.json): BUCKET}
        وثيقة سياسة:
          بيان:
          - عمل:
            - s3: GetObject
            تأثير: السماح
            الموارد:
            - arn: aws: s3 ::: $ {file (config.json): BUCKET} / *
            المالك: "*"

نطلب مورد مجموعة S3 الذي تم تكوينه لاستخدام استضافة موقع ثابت مع index.html كمستند رئيسي. دلاء S3 لسبب وجيه هي خاصة بشكل افتراضي ، لذلك نحن بحاجة إلى إنشاء سياسة دلو S3 التي تتيح الوصول العام إليها. وبدون هذه السياسة ، سيظهر زوار موقع الويب بدلاً من ذلك رسالة خطأ غير مصادقة.

بناء API

وظيفة Lambda لدينا هي المسؤولة عن أربع مهام.

  1. الاستيلاء على URL لتقصير من تقديم نموذج المستخدم.
  2. توليد رمز قصير فريد لعنوان URL.
  3. حفظ كائن إعادة التوجيه المناسب إلى S3.
  4. إرجاع مسار الكائن إلى العميل.

إنشاء المعالج

قم بإنشاء ملف جديد يسمى api.js وقم بتصدير دالة سهم باسم المؤشر والتي تأخذ ثلاث وسيطات: الحدث والسياق ورد الاتصال. سيتم توفير هذه من قبل AWS عندما يتم استدعاء المعالج. هذا الملف عبارة عن برنامج نصي Node.js ومن أجل تصدير وظيفة السهم ، يلزمك إلحاقه بالوحدة النمطية.

module.exports.handle = (حدث ، سياق ، رد اتصال) => {
}

سيتم استدعاء هذا المعالج عند تقديم طلب HTTP POST إلى نقطة النهاية الخاصة بنا. لإرجاع استجابة API ، نحتاج إلى استخدام وظيفة رد الاتصال التي يتم توفيرها كوسيطة دالة السهم الثالث. إنه رد اتصال عن طريق الخطأ يحتاج إلى وسيطين. إذا تم إكمال الطلب بنجاح ، فيجب أن يتم تمريره باعتباره الوسيطة الأولى. كائن الاستجابة الذي تم تمريره حيث تحدد الوسيطة الثانية نوع الاستجابة المطلوب إرجاعها إلى المستخدم. توليد استجابة بسيط مثل توفير كود الحالة والجسم كما هو موضح في المثال أدناه.

استجابة const = {
  كود الكود: 201 ،
  النص الأساسي: JSON.stringify ({"shortUrl": "http://example.com"})
}
رد الاتصال (فارغ ، استجابة)

يحتوي كائن السياق الذي تم تمريره باعتباره الوسيطة الثانية إلى المعالج على معلومات وقت التشغيل والتي لا نحتاج إلى الوصول إليها في هذا البرنامج التعليمي. ومع ذلك ، نحن بحاجة إلى الاستفادة من الحدث الذي تم تمريره باعتباره الوسيطة الأولى لأن هذا يحتوي على تقديم النموذج مع عنوان URL للتقصير.

تحليل الطلب

في ما يلي مثال لحدث بوابة API سيتم تمريره إلى معالجنا عندما يقوم المستخدم بإرسال نموذج. نظرًا لأننا نقوم ببناء أداة تقصير عناوين URL الخاصة بنا كتطبيق من صفحة واحدة ، فسوف نقوم بتقديم النموذج باستخدام جافا سكريبت ، وبالتالي سيكون نوع المحتوى هو التطبيق / json بدلاً من application / x-www-form-urlencoded.

{
   الموارد: '/'،
   مسار:'/'،
   httpMethod: 'المشاركة'،
   الرؤوس: {
      قبول:'*/*'،
      "قبول الترميز": "gzip، deflate"،
      "مخبأ السيطرة ':' لا ذاكرة التخزين المؤقت"،
      "CloudFront احال-بروتو ':' HTTPS،
      "CloudFront هو بين سطح المكتب عارض ':' صحيح '،
      "CloudFront-هل موبايل عارض ':' كاذبة '،
      "CloudFront هو بين التلفزيون الذكي عارض ':' كاذبة '،
      "CloudFront هو بين اللوحي عارض ':' كاذبة '،
      "CloudFront عارض-البلد ':' GB '،
      "نوع المحتوى ':' التطبيق / سلمان،
      مضيف:''،
      'وكيل المستخدم':''،
      'X-AMZ-CF-إيد': ''،
      'X-AMZN-تتبع-إيد': ''،
      "تم إعادة توجيهها X-ل':' '،
      'X-احال ميناء': '443'،
      "تم إعادة توجيهها X-بروتو ':' الشبكي"
   }،
   queryStringParameters: باطل،
   pathParameters: {}،
   stageVariables: باطل،
   requestContext: {
      مسار: '/ ديف'،
      accountId: ''،
      RESOURCEID: ''،
      المرحلة: "ديف"،
      طلب معرف:''،
      هوية:{
         cognitoIdentityPoolId: باطل،
         accountId: باطل،
         cognitoIdentityId: باطل،
         المتصل: باطل،
         مفتاح API:''،
         IP المصدر:''،
         مميزة accesskey: فارغة
         cognitoAuthenticationType: باطل،
         cognitoAuthenticationProvider: باطل،
         userArn: باطل،
         وكيل المستخدم:''،
         المستخدم: باطل
      }،
      resourcePath: '/'،
      httpMethod: 'المشاركة'،
      apiId: ''
   }،
   الهيئة: '{ "URL": "http://example.com"}،
   isBase64Encoded: كاذبة
}

نحتاج فقط إلى تقديم النموذج من الحدث ، والذي يمكننا الحصول عليه من خلال النظر في نص الطلب. يتم تخزين نص الطلب ككائن JavaScript معيّن يمكننا الاستيلاء عليه داخل معالجنا باستخدام JSON.parse (). من خلال الاستفادة من تقييم الدائرة القصيرة JavaScript ، يمكننا تعيين قيمة افتراضية لسلسلة فارغة للحالات التي لم يتم فيها إرسال عنوان URL كجزء من تقديم النموذج. يسمح لنا هذا بمعالجة الحالات التي يكون فيها عنوان URL مفقودًا وحيث يكون عنوان URL عبارة عن سلسلة فارغة على قدم المساواة.

module.exports.handle = (حدث ، سياق ، رد اتصال) => {
  واسمحوا longUrl = JSON.parse (event.body) .url || ''
}

التحقق من صحة URL

دعنا نضيف بعض التحقق من الصحة الأساسية للتحقق من أن عنوان URL المقدم شرعي. هناك طرق متعددة يمكن اتخاذها لتحقيق ذلك. ولكن لأغراض هذا البرنامج التعليمي ، سنبقي الأمر بسيطًا ونستخدم وحدة عنوان URL Node.js المدمجة. سنبني عملية التحقق من الصحة لإرجاع وعد تم حله على عنوان URL صالح وإرجاع وعد تم رفضه على عنوان URL غير صالح. يمكن ربط سلاسل الوعود في جافا سكريبت بالتتابع بحيث يتم تمرير دقة الوعد إلى معالج النجاح في التالي. سنستخدم هذه السمة من الوعود لهيكلة معالجنا. لنكتب وظيفة التحقق من الصحة باستخدام الوعود.

عنوان url = requ ('url')
التحقق من صحة الوظيفة (longUrl) {
  إذا (longUrl === '') {
    إرجاع Promise.reject ({
      statusCode: 400 ،
      الرسالة: "مطلوب عنوان URL"
    })
  }
دع parsedUrl = url.parse (longUrl)
  if (parsedUrl.protocol === null || parsedUrl.host === null) {
    إرجاع Promise.reject ({
      statusCode: 400 ،
      الرسالة: "عنوان URL غير صالح"
    })
  }
إرجاع Promise.resolve (longUrl)
}

في وظيفة التحقق من الصحة ، نتحقق أولاً من أن عنوان URL لم يتم تعيينه إلى سلسلة فارغة. إذا كان الأمر كذلك فإننا نعيد وعدا مرفوضا لاحظ كيف أن القيمة المرفوضة هي كائن يحتوي على رمز الحالة والرسالة. سنستخدمها لاحقًا لإنشاء استجابة مناسبة لواجهة برمجة التطبيقات. يؤدي تحليل الاتصال على وحدة url Node.js إلى إرجاع كائن URL بمعلومات يمكن استخراجها من عنوان URL الذي تم تمريره كوسيطة سلسلة. كجزء من التحقق من صحة عنوان URL الأساسي ، نتحقق ببساطة لمعرفة ما إذا كان يمكن استخراج بروتوكول (على سبيل المثال ، "http") ومضيف (مثل "example.com"). إذا كانت أي من هذه القيم خالية في كائن URL المرتجع ، فإننا نفترض أن عنوان URL غير صالح. إذا كان عنوان URL صالحًا ، فسنعيده كجزء من وعد تم حله.

إرجاع الرد

بعد الاستيلاء على عنوان URL من الطلب الذي نسميه بالتحقق من صحة ، ولكل خطوة إضافية من خطوات المعالج المطلوبة ، سنعود بوعد جديد في معالج نجاح الوعد السابق. معالج النجاح النهائي مسؤول عن إرجاع استجابة API من خلال وسيطة رد الاتصال الخاصة بالمقبض. سيتم التذرع به لاستجابات خطأ واجهة برمجة التطبيقات الناتجة عن الوعود المرفوضة وكذلك استجابات واجهة برمجة التطبيقات الناجحة.

module.exports.handle = (حدث ، سياق ، رد اتصال) => {
  واسمحوا longUrl = JSON.parse (event.body) .url || ''
  التحقق من صحة (longUrl)
    .ثم (الوظيفة (المسار) {
      دع استجابة = buildResponse (200 ، "نجاح" ، مسار)
      عودة وعد. حل (استجابة)
    })
    .catch (function (err) {
      دع الاستجابة = buildResponse (err.statusCode ، err.message)
      عودة وعد. حل (استجابة)
    })
    .ثم (الوظيفة (الاستجابة) {
      رد الاتصال (فارغ ، استجابة)
    })
}
وظيفة buildResponse (statusCode ، message ، path = false) {
  دع الجسم = {message}
  إذا (مسار) الجسم ['المسار'] = المسار
  
  إرجاع {
    الرؤوس: {
      "التحكم في الوصول-السماح-المنشأ": '*'
    }،
    statusCode: statusCode ،
    الجسم: JSON.Stringify (الجسم)
  }
}

إنشاء رمز URL قصير

يجب أن تكون واجهة برمجة التطبيقات قادرة على إنشاء رموز مختصرة لعناوين URL ، والتي يتم تمثيلها كأسماء ملفات في المجموعة S3. نظرًا لأن الرمز المختصر هو مجرد اسم ملف ، فهناك درجة كبيرة من المرونة في كيفية تكوينه. بالنسبة للرمز المختصر الخاص بنا ، سنستخدم سلسلة أبجدية رقمية مكونة من 7 أرقام تتكون من كل من الأحرف الكبيرة والصغيرة ، وهذا يترجم إلى 62 مجموعة ممكنة لكل حرف. سنستخدم العودية لإنشاء رمز قصير عن طريق اختيار حرف واحد في وقت واحد حتى يتم اختيار سبعة.

الدالة generPath (path = '') {
  دع الحروف = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  اسمحوا الموضع = Math.floor (Math.random () * character.length)
  اجعل الحرف = character.charAt (الموضع)
if (path.length === 7) {
  مسار العودة
}
إرجاع generPath (مسار + حرف)
}

في حين أن فرصة إنشاء نفس الرمز القصير بشكل عشوائي ضئيلة (هناك بالفعل فرصة 0.0000000000000000000000008063365516 بأن يكون الرمزان القصيران متماثلين) ، نحن بحاجة إلى التحقق مما إذا كان الرمز القصير الذي تم إنشاؤه قيد الاستخدام بالفعل ، والذي يمكننا القيام به باستخدام AWS SDK. هناك طريقة headObject على خدمة S3 التي تقوم بتحميل البيانات الأولية للكائن. يمكننا استخدام هذا لاختبار ما إذا كان كائن يحمل نفس الاسم موجودًا بالفعل كما هو الحال عندما لم يتم العثور على كائن بالوعد بالرمز تم رفض NotFound. يشير هذا الوعد المرفوض إلى أن الرمز القصير مجاني ويمكن استخدامه. استدعاء headObject هو أكثر أداءً من اختبار ما إذا كان الكائن موجودًا من خلال getObject ، والذي يقوم بتحميل الكائن بالكامل.

const AWS = تتطلب ('aws-sdk')
const S3 = AWS.S3 () جديدة
الوظيفة isPathFree (path) {
  إرجاع S3.headObject (buildRedirect (المسار)).
    .then (() => Promise.resolve (false))
    .catch (function (err) {
      if (err.code == 'NotFound') {
        إرجاع Promise.resolve (صواب)
      } آخر {
        إرجاع Promise.reject (err)
      }
    })
}
الدالة buildRedirect (المسار ، longUrl = خطأ) {
  السماح بإعادة التوجيه = {
    "دلو": config.BUCKET ،
    "مفتاح": المسار
  }
إذا (longUrl) {
    إعادة توجيه ['WebsiteRedirectLocation'] = longUrl
  }
إعادة توجيه
}

يمكننا استخدام isPathFree لإيجاد مسار كائن فريد بشكل متكرر.

وظيفة getPath () {
  إرجاع وعد جديد (وظيفة (حل ، رفض) {
    اسمح للمسار = createPath ()
    isPathFree (مسار)
      .ثم (الوظيفة (isFree) {
        عودة isFree؟ العزم (المسار): العزم (getPath ())
      })
  })
}

مع الاستفادة من القدرة على سلسلة الوعود ، نرجع استدعاء جديد من getPath إذا كانت isPathFree تُرجع خطأ.

لحفظ كائن بعد العثور على رمز قصير فريد ، نحتاج فقط إلى استدعاء طريقة putObject في خدمة AWS SDK S3. دعنا نختتم هذا في وظيفة تحل الرمز القصير إذا كانت استدعاء الأسلوب putObject ناجحة وإرجاع كائن خطأ لإنشاء استجابة API إذا لم تنجح.

وظيفة saveRedirect (إعادة التوجيه) {
  إرجاع S3.putObject (إعادة توجيه) .promise ()
    .then (() => Promise.resolve (إعادة التوجيه ['Key']))
    .catch (() => Promise.reject ({
      statusCode: 500 ،
      رسالة: "خطأ في حفظ إعادة التوجيه"
  })
}

باستخدام الوظائف المذكورة أعلاه ، يمكننا إضافة معالجين جديدين لنجاح الوعد لإنهاء نقطة نهاية واجهة برمجة التطبيقات. نحتاج إلى إرجاع getPath من معالج نجاح الوعد الأول الذي سيعمل على حل رمز قصير خاص بعنوان URL. إرجاع saveRedirect مع كائن إعادة توجيه تم إنشاؤه باستخدام هذا الرمز القصير الفريد في معالج النجاح الثاني سيوفر الكائن في مجموعة S3. يمكن بعد ذلك إرجاع مسار هذا الكائن إلى العميل كجزء من استجابة API. يجب أن يكون معالجنا مكتملًا الآن.

module.exports.handle = (حدث ، سياق ، رد اتصال) => {
  واسمحوا longUrl = JSON.parse (event.body) .url || ''
  التحقق من صحة (longUrl)
    .ثم (الدالة () {
      إرجاع getPath ()
    })
    .ثم (الوظيفة (المسار) {
      السماح بإعادة التوجيه = buildRedirect (المسار ، longUrl)
      إرجاع saveRedirect (إعادة التوجيه)
    })
    .ثم (الوظيفة (المسار) {
      دع استجابة = buildResponse (200 ، "نجاح" ، مسار)
      عودة وعد. حل (استجابة)
    })
    .catch (function (err) {
      دع الاستجابة = buildResponse (err.statusCode ، err.message)
      عودة وعد. حل (استجابة)
    })
    .ثم (الوظيفة (الاستجابة) {
      رد الاتصال (فارغ ، استجابة)
    })
}

نشر API

تشغيل نشر serverless في المحطة الطرفية لنشر API إلى AWS. سيؤدي هذا إلى إعداد مجموعة S3 الخاصة بنا وإرجاع عنوان URL لنقطة النهاية. اجعل عنوان URL الخاص بنقطة النهاية في متناول يديك لأننا سنحتاج إليه لاحقًا.

Serverless: خدمة التغليف ...
Serverless: باستثناء تبعيات التطوير ...
Serverless: تحميل ملف CloudFormation إلى S3 ...
Serverless: جارٍ تحميل التحف ...
Serverless: تحميل ملف .zip للخدمة إلى S3 (5.44 MB) ...
Serverless: التحقق من صحة القالب ...
Serverless: تحديث المكدس ...
Serverless: التحقق من تقدم تحديث المكدس ...
..............
Serverless: تم الانتهاء من تحديث المكدس ...
معلومات الخدمة
الخدمة: serverless-url-shortener
المرحلة: ديف
المنطقة: eu-west-1
المكدس: serverless-url-shortener-dev
مفاتيح api:
  لا شيء
النهاية:
  POST - https://t2fgbcl26h.execute-api.eu-west-1.amazonaws.com/dev/
المهام:
  store: serverless-url-shortener-dev-store
Serverless: إزالة إصدارات الخدمة القديمة ...

خلق الواجهة الأمامية

للمساعدة في تصميم الواجهة الأمامية ، سنستخدم إطار عمل PaperCSS. سنلتقط مسجًا لتبسيط العمل مع DOM وإجراء استعلامات AJAX. تجدر الإشارة إلى أنه بالنسبة لبيئة الإنتاج ، قد ترغب في الحصول على معتمدين أخف وزناً ، لكن نظرًا لأن هذا مجرد برنامج تعليمي ، أشعر أنه مقبول.

قم بإنشاء مجلد ثابت حتى يكون لدينا مكان لتخزين رمز الواجهة الأمامية الخاص بنا.

تحميل التبعيات

احفظ نسخة من paper.min.css و jquery-3.2.1.min.js في مجلدنا الثابت الذي تم إنشاؤه حديثًا ، فهذه الإصدارات هي إصدارات مصغرة من إطار عمل PaperCSS ومكتبة مسج على التوالي.

أضف HTML

قم بإنشاء ملف جديد يسمى index.html داخل المجلد الثابت وإضافة HTML المطلوب. نحتاج إلى نموذج يحتوي على إدخال URL وزر لإرسال النموذج. نحتاج أيضًا إلى مكان لوضع نتيجة لأية مكالمات واجهة برمجة التطبيقات ، والتي ستكون من أجل مكالمة API الناجحة عنوان URL المختصر وللمكالمة غير الناجحة لواجهة برمجة التطبيقات ستكون هذه هي رسالة الخطأ.



<رئيس>
  
  
   url server shortener 
  

<نمط>
  * {
    محاذاة النص: المركز ؛
  }
  #message {
    عرض لا شيء؛
  }


  
    
      

عنوان url بدون خادم       
        
                     <مساهمة             الطبقة = "إدخال كتلة"             اسم = "URL"             اكتب = "URL"             معرف = "رابط"             الإكمال التلقائي = "إيقاف"             المطلوب>                  
        <مساهمة           الطبقة = "ورقة BTN"           اكتب = "إرسال"           القيمة = "اختصار الرابط">              

                   عرض هذا المشروع على جيثب                        

على الرغم من عدم ظهوره في مقطع التعليمات البرمجية أعلاه للإيجاز ، تأكد من تعيين إجراء النموذج على نقطة نهاية واجهة برمجة التطبيقات التي تم عرضها عند تشغيل عملية النشر بدون خادم. إذا لم يعد بإمكانك الوصول إلى مخرجاتك الطرفية من هذا النشر ، فيمكنك معرفة عنوان URL لنقطة النهاية من خلال أمر معلومات بدون خادم.

تقديم طلبات API

قبل كتابة جافا سكريبت لتقديم طلبات إلى واجهة برمجة التطبيقات الخاصة بنا ، دعونا أولاً نقوم بتحميل jQuery عن طريق إلحاق علامة نص برمجية قبل والرجوع إلى الملف المصغر الذي قمنا بتنزيله مسبقًا.

الآن أضف زوجًا آخر من علامات البرنامج النصي أسفل وداخله ، فلننشئ وظيفة يمكن استخدامها لعرض رسالة إلى المستخدم باستخدام div message في القالب الذي تم إعداده للعرض: لا شيء افتراضيًا عند تحميل الصفحة. لإظهار رسالة ، يمكننا ببساطة تعيين النص داخل هذا div باستخدام text () وتبديل العرض باستخدام show ().