Thứ tư, 20/03/2019 | 00:00 GMT+7

Cách sử dụng API Web trong Python 3

Giao diện API hoặc A pplication P rogram I cho phép các nhà phát triển tích hợp ứng dụng này với ứng dụng khác. Chúng tiết lộ một số hoạt động bên trong của chương trình một cách hạn chế.

Bạn có thể sử dụng API để lấy thông tin từ các chương trình khác hoặc để tự động hóa những việc bạn thường làm trong trình duyệt web của bạn . Đôi khi bạn có thể sử dụng API để làm những việc mà bạn không thể làm theo bất kỳ cách nào khác. Một số lượng đáng ngạc nhiên thuộc tính web cung cấp các API dựa trên web cùng với trang web hoặc ứng dụng di động quen thuộc hơn, bao gồm Twitter, Facebook, GitHub và DigitalOcean.

Nếu bạn đã làm theo cách của bạn thông qua một số hướng dẫn về cách viết mã bằng Python 3 và bạn thấy phù hợp với cú pháp, cấu trúc và một số hàm tích hợp của Python, bạn có thể viết các chương trình Python tận dụng các API yêu thích của bạn .

Trong hướng dẫn này, bạn sẽ học cách sử dụng Python với API DigitalOcean để truy xuất thông tin về account DigitalOcean của bạn. Sau đó, ta sẽ xem xét cách bạn có thể áp dụng những gì bạn đã học được vào API của GitHub .

Khi bạn hoàn thành, bạn sẽ hiểu các khái niệm phổ biến trên các API web và bạn sẽ có quy trình từng bước và các mẫu mã làm việc mà bạn có thể sử dụng để thử API từ các dịch vụ khác.

Yêu cầu

Trước khi bắt đầu hướng dẫn này, bạn cần những thứ sau:

Bước 1 - Làm quen với API

Bước đầu tiên trong việc sử dụng một API mới là tìm tài liệu và lấy vòng bi của bạn. Tài liệu API DigitalOcean bắt đầu tại https://developers.digitalocean.com/ . Để tìm các API cho các dịch vụ khác, hãy tìm kiếm tên của trang web và “API” - không phải tất cả các dịch vụ đều quảng cáo chúng trên trang đầu của chúng.

Một số dịch vụ có shell bọc API . Shell bọc API là mã mà bạn cài đặt trên hệ thống của bạn để làm cho các API dễ sử dụng hơn bằng ngôn ngữ lập trình bạn đã chọn. Hướng dẫn này không sử dụng bất kỳ shell bọc nào bởi vì chúng ẩn nhiều hoạt động bên trong của các API và thường không tiết lộ mọi thứ mà API có thể làm. Shell bọc có thể tuyệt vời khi bạn muốn hoàn thành việc gì đó một cách nhanh chóng, nhưng hiểu rõ về những gì bản thân các API có thể làm sẽ giúp bạn quyết định xem shell bọc có phù hợp với mục tiêu của bạn hay không.

Trước tiên, hãy xem Giới thiệu API DigitalOcean tại https://developers.digitalocean.com/documentation/v2/ và cố gắng chỉ hiểu những điều cơ bản về cách gửi yêu cầu và những gì mong đợi trong phản hồi. Đến đây, bạn chỉ đang cố gắng học ba điều:

  1. Yêu cầu trông như thế nào? Có phải tất cả chúng chỉ là URL? Đối với các yêu cầu chi tiết hơn, dữ liệu được định dạng như thế nào? Nó thường là JSON hoặc các tham số chuỗi truy vấn như trình duyệt web sử dụng, nhưng một số sử dụng XML hoặc định dạng tùy chỉnh.
  2. Phản hồi trông như thế nào? Các tài liệu API sẽ hiển thị các yêu cầu và phản hồi mẫu. Bạn sẽ nhận được JSON, XML hoặc một số loại phản hồi khác?
  3. Điều gì đi vào tiêu đề yêu cầu hoặc phản hồi? Thông thường, tiêu đề yêu cầu bao gồm mã thông báo xác thực của bạn và tiêu đề phản hồi cung cấp thông tin hiện tại về việc bạn sử dụng dịch vụ, chẳng hạn như mức độ bạn đạt đến giới hạn tỷ lệ.

API DigitalOcean sử dụng các phương thức HTTP (đôi khi được gọi là động từ ) để cho biết bạn đang cố đọc thông tin hiện có, tạo thông tin mới hay xóa nội dung nào đó. Phần này của tài liệu giải thích những phương pháp nào được sử dụng và cho những mục đích nào. Nói chung, yêu cầu GET đơn giản hơn yêu cầu ĐĂNG, nhưng khi hoàn thành ở đây, bạn sẽ không nhận thấy nhiều sự khác biệt.

Phần tiếp theo của tài liệu API thảo luận về cách server sẽ phản hồi các yêu cầu của bạn. Nói chung, một yêu cầu thành công hoặc không thành công. Khi nó không thành công, nguyên nhân là do yêu cầu có vấn đề gì đó hoặc sự cố trên server . Tất cả thông tin này được truyền đạt bằng mã trạng thái HTTP , là các số có 3 chữ số được chia thành các loại.

  • Chuỗi 200 nghĩa là “thành công” - yêu cầu của bạn là hợp lệ và phản hồi là những gì theo logic từ đó.
  • Chuỗi 400 nghĩa là “yêu cầu không hợp lệ” - có gì đó không ổn với yêu cầu, vì vậy server không xử lý nó như bạn muốn. Nguyên nhân phổ biến gây ra lỗi cấp độ HTTP 400 là các yêu cầu bị định dạng sai và sự cố xác thực.
  • Chuỗi 500 nghĩa là "lỗi server " - yêu cầu của bạn có thể đã ổn, nhưng server không thể cung cấp cho bạn phản hồi tốt ngay bây giờ vì những lý do ngoài tầm kiểm soát của bạn. Những điều này hiếm khi xảy ra, nhưng bạn cần lưu ý khả năng xảy ra để có thể xử lý chúng trong mã của bạn .

Mã của bạn phải luôn kiểm tra mã trạng thái HTTP để tìm bất kỳ phản hồi nào trước khi cố gắng làm bất cứ điều gì với nó. Nếu bạn không làm điều này, bạn sẽ thấy mình lãng phí thời gian khắc phục sự cố với thông tin không đầy đủ.

Đến đây bạn đã có ý tưởng chung về cách gửi yêu cầu và những gì cần tìm trong phản hồi, đã đến lúc gửi yêu cầu đầu tiên đó.

Bước 2 - Lấy thông tin từ API Web

Tài khoản DigitalOcean của bạn bao gồm một số thông tin quản trị mà bạn có thể chưa thấy trong giao diện user Web. Một API có thể cung cấp cho bạn một cái nhìn khác về thông tin quen thuộc. Việc chỉ nhìn thấy chế độ xem thay thế này đôi khi có thể khơi dậy ý tưởng về những gì bạn có thể cần làm với API hoặc tiết lộ các dịch vụ và tùy chọn mà bạn chưa biết.

Hãy bắt đầu bằng cách tạo một dự án cho các tập lệnh của ta . Tạo một folder mới cho dự án có tên là apis :

  • mkdir apis

Sau đó, chuyển vào folder mới này:

  • cd apis

Tạo một virtualenv mới cho dự án này:

  • python3 -m venv apis

Kích hoạt virtualenv:

  • source apis/bin/activate

Sau đó, cài đặt thư viện yêu cầu , mà ta sẽ sử dụng trong các tập lệnh của bạn để thực hiện các yêu cầu HTTP trong các tập lệnh của ta :

  • pip install requests

Với môi trường được cấu hình , hãy tạo một file Python mới có tên do_get_account.py và mở nó trong editor của bạn. Bắt đầu chương trình này bằng cách nhập các thư viện để làm việc với các yêu cầu JSON và HTTP.

do_get_account.py
import json import requests 

Các câu lệnh import này tải mã Python cho phép ta làm việc với định dạng dữ liệu JSON và giao thức HTTP. Ta đang sử dụng các thư viện này vì ta không quan tâm đến chi tiết về cách gửi yêu cầu HTTP hoặc cách phân tích cú pháp và tạo JSON hợp lệ; ta chỉ muốn sử dụng chúng để hoàn thành các nhiệm vụ này. Tất cả các tập lệnh của ta trong hướng dẫn này sẽ bắt đầu như thế này.

Tiếp theo, ta muốn cài đặt một số biến để lưu giữ thông tin sẽ giống nhau trong mọi yêu cầu. Điều này giúp ta không phải nhập lại nhiều lần và cung cấp cho ta một nơi duy nhất để cập nhật trong trường hợp có bất kỳ điều gì thay đổi. Thêm các dòng này vào file , sau các câu lệnh import .

do_get_account.py
... api_token = 'your_api_token' api_url_base = 'https://api.digitalocean.com/v2/' 

Biến api_token là một chuỗi chứa mã thông báo API DigitalOcean của bạn. Thay thế giá trị trong ví dụ bằng mã thông báo của bạn . Biến api_url_base là chuỗi bắt đầu mọi URL trong API DigitalOcean. Ta sẽ thêm vào nó nếu cần sau này trong mã.

Tiếp theo, ta cần cài đặt tiêu đề yêu cầu HTTP theo cách mà tài liệu API mô tả. Thêm các dòng này vào file để cài đặt từ điển chứa các tiêu đề yêu cầu của bạn:

do_get_account.py
... headers = {'Content-Type': 'application/json',            'Authorization': 'Bearer {0}'.format(api_token)} 

Điều này đặt hai tiêu đề cùng một lúc. Tiêu đề Content-Type cho server biết dữ liệu có định dạng JSON trong phần nội dung của yêu cầu. Tiêu đề Authorization cần phải bao gồm mã thông báo của ta , vì vậy ta sử dụng logic định dạng chuỗi của Python để chèn biến api_token của ta vào chuỗi khi ta tạo chuỗi. Ta có thể đặt mã thông báo ở đây dưới dạng một chuỗi theo nghĩa đen, nhưng việc tách nó ra sẽ làm cho một số thứ trở nên dễ dàng hơn:

  • Nếu bạn cần thay thế mã thông báo, sẽ dễ dàng hơn để biết nơi thực hiện điều đó khi đó là một biến riêng biệt.
  • Nếu bạn muốn chia sẻ mã của bạn với ai đó, việc xóa mã thông báo API của bạn sẽ dễ dàng hơn và bạn bè của bạn dễ dàng biết vị trí đặt mã của họ hơn.
  • Nó tự ghi lại. Nếu mã thông báo API chỉ được sử dụng dưới dạng một chuỗi ký tự, thì ai đó đang đọc mã của bạn có thể không hiểu những gì họ đang xem.

Bây giờ ta đã có các chi tiết cài đặt này, đã đến lúc thực sự gửi yêu cầu. Xu hướng của bạn có thể là chỉ bắt đầu tạo và gửi các yêu cầu, nhưng có một cách tốt hơn. Nếu bạn đặt logic này vào một hàm xử lý việc gửi yêu cầu và đọc phản hồi, bạn sẽ phải suy nghĩ rõ ràng hơn một chút về những gì bạn đang làm. Bạn cũng sẽ nhận được mã giúp cho việc thử nghiệm và sử dụng lại đơn giản hơn. Đó là những gì ta sẽ làm.

Hàm này sẽ sử dụng các biến bạn đã tạo để gửi yêu cầu và trả về thông tin account trong từ điển Python.

Để giữ cho logic rõ ràng ở giai đoạn đầu này, ta sẽ không thực hiện bất kỳ xử lý lỗi chi tiết nào, nhưng ta sẽ sớm bổ sung điều đó.

Xác định chức năng tìm nạp thông tin account . Luôn luôn là một ý kiến hay khi đặt tên cho một hàm theo chức năng của nó: Hàm này lấy thông tin account , vì vậy ta sẽ gọi nó là get_account_info :

do_get_account.py
... def get_account_info():      api_url = '{0}account'.format(api_url_base)      response = requests.get(api_url, headers=headers)      if response.status_code == 200:         return json.loads(response.content.decode('utf-8'))     else:         return None 

Ta xây dựng giá trị cho api_url bằng cách sử dụng phương pháp định dạng chuỗi của Python tương tự như cách ta sử dụng nó trong tiêu đề; ta thêm URL cơ sở của API vào trước account chuỗi để lấy URL https://api.digitalocean.com/v2/account , URL sẽ trả về thông tin account .

Biến response chứa một đối tượng được tạo bởi mô-đun requests Python. Dòng này gửi yêu cầu đến URL mà ta đã thực hiện với các tiêu đề mà ta đã xác định ở đầu tập lệnh và trả về phản hồi từ API.

Tiếp theo, ta xem xét mã trạng thái HTTP của phản hồi.

Nếu đó là 200 , một phản hồi thành công, thì ta sử dụng hàm loads của module json để tải một chuỗi dưới dạng JSON. Tải chuỗi ta là nội dung của response đối tượng, response.content . Phần .decode('utf-8') cho Python biết rằng nội dung này được mã hóa bằng cách sử dụng bộ ký tự UTF-8, như tất cả các phản hồi từ API DigitalOcean. Mô-đun json tạo một đối tượng từ đó mà ta sử dụng làm giá trị trả về cho hàm này.

Nếu phản hồi không phải200 , thì ta trả về None , là một giá trị đặc biệt trong Python mà ta có thể kiểm tra khi gọi hàm này. Bạn sẽ nhận thấy rằng ta chỉ bỏ qua bất kỳ lỗi nào tại thời điểm này. Điều này là để giữ cho logic “thành công” rõ ràng. Ta sẽ sớm bổ sung kiểm tra lỗi toàn diện hơn.

Bây giờ hãy gọi hàm này, kiểm tra đảm bảo rằng nó có phản hồi tốt và in ra các chi tiết mà API trả về:

do_get_account.py
... account_info = get_account_info()  if account_info is not None:     print("Here's your info: ")     for k, v in account_info['account'].items():         print('{0}:{1}'.format(k, v))  else:     print('[!] Request Failed') 

account_info = get_account_info() đặt biến account_info thành bất cứ giá trị nào quay lại từ lệnh gọi get_account_info() , vì vậy nó sẽ là giá trị đặc biệt None hoặc nó sẽ là tập hợp thông tin về account .

Nếu không phải là None , thì ta in ra từng phần thông tin trên dòng riêng của nó bằng cách sử dụng phương thức items() mà tất cả các từ điển Python đều có.

Nếu không (nghĩa là nếu account_infoNone ), ta sẽ in một thông báo lỗi.

Hãy tạm dừng một phút ở đây. Câu lệnh if này với âm kép trong nó thoạt đầu có thể cảm thấy khó xử, nhưng nó là một thành ngữ Python phổ biến. Ưu điểm của nó là giữ cho mã chạy thành công rất gần với điều kiện thay vì sau khi xử lý các trường hợp lỗi.

Bạn có thể làm theo cách khác nếu thích và có thể là một bài tập tốt để tự viết mã đó. Thay vì if account_info is not None: bạn có thể bắt đầu với if account_info is None: và xem phần còn lại rơi vào vị trí như thế nào.

Lưu tập lệnh và dùng thử:

  • python do_get_account.py

Đầu ra sẽ giống như sau:

Output
Here's your info: server_limit:25 email:sammy@digitalocean.com status:active floating_ip_limit:3 email_verified:True uuid:123e4567e89b12d3a456426655440000 status_message:

Đến đây bạn biết cách lấy dữ liệu từ một API. Tiếp theo, ta sẽ chuyển sang một thứ thú vị hơn một chút - sử dụng API để thay đổi dữ liệu.

Bước 3 - Sửa đổi thông tin trên server

Sau khi thực hành với yêu cầu chỉ đọc, đã đến lúc bắt đầu áp dụng các thay đổi . Hãy khám phá điều này bằng cách sử dụng Python và API DigitalOcean để thêm SSH key vào account DigitalOcean của bạn.

Trước tiên, hãy xem tài liệu API cho SSH key , có sẵn tại /.2808.anews .

API cho phép bạn liệt kê các SSH key hiện tại trên account của bạn và cũng cho phép bạn thêm các khóa mới. Yêu cầu lấy danh sách SSH key rất giống yêu cầu lấy thông tin account . Tuy nhiên, phản hồi là khác nhau: không giống như một account , bạn có thể có 0, một hoặc nhiều SSH key .

Tạo một file mới cho tập lệnh này có tên do_ssh_keys.py và bắt đầu nó giống hệt như tập lệnh cuối cùng. Nhập các module jsonrequests để bạn không phải lo lắng về các chi tiết của JSON hoặc giao thức HTTP. Sau đó, thêm mã thông báo API DigitalOcean của bạn làm biến và cài đặt tiêu đề yêu cầu trong từ điển.

do_ssh_keys.py
import json import requests   api_token = 'your_api_token' api_url_base = 'https://api.digitalocean.com/v2/' headers = {'Content-Type': 'application/json',            'Authorization': 'Bearer {0}'.format(api_token)} 

Hàm ta sẽ tạo để lấy SSH key tương tự như hàm ta đã sử dụng để lấy thông tin account , nhưng lần này ta sẽ xử lý lỗi trực tiếp hơn.

Đầu tiên, ta sẽ thực hiện cuộc gọi API và lưu trữ các phản ứng trong một response biến phản ứng. Mặc dù vậy, api_url sẽ không giống như trong tập lệnh trước; lúc này nó cần trỏ đến https://api.digitalocean.com/v2/account/keys .

Thêm mã này vào tập lệnh:

do_ssh_keys.py
... def get_ssh_keys():      api_url = '{0}account/keys'.format(api_url_base)      response = requests.get(api_url, headers=headers) 

Bây giờ, hãy thêm một số xử lý lỗi bằng cách xem mã trạng thái HTTP trong phản hồi. Nếu là 200 , ta sẽ trả về nội dung của câu trả lời dưới dạng từ điển, giống như ta đã làm trước đây. Nếu đó là bất kỳ điều gì khác, ta sẽ in một thông báo lỗi hữu ích được liên kết với loại mã trạng thái và sau đó trả về None .

Thêm các dòng này vào hàm get_ssh_keys :

do_ssh_keys.py
...      if response.status_code >= 500:         print('[!] [{0}] Server Error'.format(response.status_code))         return None     elif response.status_code == 404:         print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))         return None       elif response.status_code == 401:         print('[!] [{0}] Authentication Failed'.format(response.status_code))         return None     elif response.status_code == 400:         print('[!] [{0}] Bad Request'.format(response.status_code))         return None     elif response.status_code >= 300:         print('[!] [{0}] Unexpected Redirect'.format(response.status_code))         return None     elif response.status_code == 200:         ssh_keys = json.loads(response.content.decode('utf-8'))         return ssh_keys     else:         print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))     return None 

Mã này xử lý sáu điều kiện lỗi khác nhau bằng cách xem mã trạng thái HTTP trong phản hồi.

  • 500 trở lên cho biết có sự cố trên server . Những điều này hiếm khi xảy ra và chúng không phải do sự cố với yêu cầu, vì vậy ta chỉ in mã trạng thái.
  • 404 nghĩa là "không tìm thấy", có thể bắt nguồn từ lỗi đánh máy trong URL. Đối với lỗi này, ta in mã trạng thái và URL dẫn đến lỗi này để bạn có thể biết tại sao nó không thành công.
  • 401 nghĩa là xác thực không thành công. Nguyên nhân rất có thể là do api_key không chính xác hoặc bị thiếu.
  • Mã trong phạm vi 300 chỉ ra một chuyển hướng. API DigitalOcean không sử dụng chuyển hướng, vì vậy, điều này sẽ không bao giờ xảy ra, nhưng trong khi ta đang xử lý lỗi, kiểm tra không hại gì. Rất nhiều lỗi gây ra bởi những thứ mà lập trình viên nghĩ rằng không bao giờ nên xảy ra.
  • 200 nghĩa là yêu cầu đã được xử lý thành công. Đối với điều này, ta không in bất cứ điều gì. Ta chỉ trả lại các khóa ssh dưới dạng một đối tượng JSON, sử dụng cùng một cú pháp mà ta đã sử dụng trong tập lệnh trước đó.
  • Nếu mã phản hồi là bất kỳ thứ gì khác, ta sẽ in mã trạng thái dưới dạng “lỗi không mong muốn”.

Điều đó sẽ xử lý bất kỳ lỗi nào mà ta có thể gặp phải khi gọi API. Đến đây, ta có thông báo lỗi và đối tượng None hoặc ta đã thành công và đối tượng JSON chứa không hoặc nhiều SSH key . Bước tiếp theo của ta là in chúng ra:

do_ssh_keys.py
...  ssh_keys = get_ssh_keys()  if ssh_keys is not None:     print('Here are your keys: ')     for key, details in enumerate(ssh_keys['ssh_keys']):         print('Key {}:'.format(key))         for k, v in details.items():             print('  {0}:{1}'.format(k, v)) else:     print('[!] Request Failed') 

Vì phản hồi chứa danh sách (hoặc mảng) SSH key , ta muốn lặp lại toàn bộ danh sách để xem tất cả các khóa. Ta sử dụng phương pháp enumerate của Python cho việc này. Điều này tương tự như phương pháp items có sẵn cho từ điển, nhưng nó hoạt động với các danh sách.

Ta sử dụng enumerate chứ không chỉ là vòng lặp for , bởi vì ta muốn có thể cho biết ta đang ở bao xa trong danh sách đối với bất kỳ khóa nhất định nào.

Thông tin của mỗi khóa được trả về dưới dạng từ điển, vì vậy ta sử dụng mã tương tự for k,v in details.items(): mà ta đã sử dụng trên từ điển thông tin account trong tập lệnh trước.

Chạy tập lệnh này và bạn sẽ nhận được danh sách các SSH key đã có trong account của bạn .

  • python get_ssh_keys.py

Đầu ra sẽ giống như thế này, tùy thuộc vào số lượng SSH key bạn đã có trong account của bạn .

Output
Here are your keys: Kcy 0: id:280518 name:work fingerprint:96:f7:fb:9f:60:9c:9b:f9:a9:95:01:5c:5c:2c:d5:a0 public_key:ssh-rsa AAAAB5NzaC1yc2cAAAADAQABAAABAQCwgr9Fzc/YTD/V2Ka5I52Rx4I+V2Ka5I52Rx4Ir5LKSCqkQ1Cub+... sammy@work Kcy 1: id:290536 name:home fingerprint:90:1c:0b:ac:fa:b0:25:7c:af:ab:c5:94:a5:91:72:54 public_key:ssh-rsa AAAAB5NzaC1yc2cAAAABJQAAAQcAtTZPZmV96P9ziwyr5LKSCqkQ1CubarKfK5r7iNx0RNnlJcqRUqWqSt... sammy@home

Đến đây bạn có thể liệt kê các SSH key trên account của bạn , tập lệnh cuối cùng của bạn ở đây sẽ là một tập lệnh thêm khóa mới vào danh sách.

Trước khi có thể thêm SSH key mới, ta cần tạo một khóa. Để có cách xử lý đầy đủ hơn về bước này, hãy xem hướng dẫn Cách cài đặt SSH key .

Tuy nhiên, đối với mục đích của ta , ta chỉ cần một key đơn giản. Thực thi lệnh này để tạo một lệnh mới trên Linux, BSD hoặc MacOS. Bạn có thể làm điều này trên Server hiện có, nếu bạn thích.

  • ssh-keygen -t rsa

Khi được yêu cầu , hãy nhập file để lưu khóa và không cung cấp passphrase (password bảo vệ) .

Output
Generating public/private rsa key pair. Enter file in which to save the key (/home/sammy/.ssh/id_rsa): /home/sammy/.ssh/sammy Created directory '/home/sammy/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/sammy/.ssh/sammy. Your public key has been saved in /home/sammy/.ssh/sammy.pub. ...

Ghi lại nơi lưu file public key , vì bạn cần nó cho tập lệnh.

Bắt đầu một tập lệnh Python mới và gọi nó là add_ssh_key.py và bắt đầu nó giống như những tập lệnh khác:

add_ssh_key.py
 import json import requests   api_token = 'your_api_token' api_url_base = 'https://api.digitalocean.com/v2/' headers = {'Content-Type': 'application/json',            'Authorization': 'Bearer {0}'.format(api_token)} 

Ta sẽ sử dụng một hàm để thực hiện yêu cầu của bạn , nhưng hàm này sẽ hơi khác một chút.

Tạo một hàm có tên add_ssh_key sẽ chấp nhận hai đối số: tên để sử dụng cho SSH key mới và tên file của chính khóa trên hệ thống local của bạn. Hàm sẽ đọc file và thực hiện yêu cầu HTTP POST , thay vì GET :

add_ssh_key.py
...  def add_ssh_key(name, filename):      api_url = '{0}account/keys'.format(api_url_base)      with open(filename, 'r') as f:         ssh_key = f.readline()      ssh_key = {'name': name, 'public_key': ssh_key}      response = requests.post(api_url, headers=headers, json=ssh_key) 

Dòng with open(filename, 'r') as f: mở file ở chế độ chỉ đọc và dòng tiếp theo đọc dòng đầu tiên (và duy nhất) từ file , lưu trữ trong biến ssh_key .

Tiếp theo, ta tạo một từ điển Python có tên ssh_key với các tên và giá trị mà API mong đợi.

Tuy nhiên, khi ta gửi yêu cầu, có một số thứ mới hơn một chút. Đó là POST chứ không phải GET và ta cần gửi ssh_key trong phần nội dung của yêu cầu POST , được mã hóa dưới dạng JSON. Mô-đun requests sẽ xử lý các chi tiết cho ta ; json=ssh_key requests.post nó sử dụng phương thức POST và bao gồm json=ssh_key yêu cầu nó gửi biến ssh_key trong phần nội dung của yêu cầu, được mã hóa dưới dạng JSON.

Theo API, phản hồi sẽ là HTTP 201 khi thành công, thay vì 200 và phần nội dung của phản hồi sẽ chứa các chi tiết của khóa mà ta vừa thêm vào.

Thêm mã xử lý lỗi sau vào hàm add_ssh_key . Nó tương tự như tập lệnh trước, ngoại trừ lần này ta phải tìm mã 201 thay vì 200 để thành công:

add_ssh_key.py
...     if response.status_code >= 500:         print('[!] [{0}] Server Error'.format(response.status_code))         return None     elif response.status_code == 404:         print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))         return None     elif response.status_code == 401:         print('[!] [{0}] Authentication Failed'.format(response.status_code))         return None     elif response.status_code >= 400:         print('[!] [{0}] Bad Request'.format(response.status_code))         print(ssh_key )         print(response.content )         return None     elif response.status_code >= 300:         print('[!] [{0}] Unexpected redirect.'.format(response.status_code))         return None     elif response.status_code == 201:         added_key = json.loads(response.content)         return added_key     else:         print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))         return None 

Hàm này, giống như các hàm trước, trả về None hoặc nội dung phản hồi, vì vậy ta sử dụng phương pháp tương tự như trước để kiểm tra kết quả.

Tiếp theo, gọi hàm và xử lý kết quả. Chuyển đường dẫn đến SSH key mới tạo của bạn làm đối số thứ hai:

add_ssh_key.py
... add_response = add_ssh_key('tutorial_key', '/home/sammy/.ssh/sammy.pub')  if add_response is not None:     print('Your key was added: ' )     for k, v in add_response.items():         print('  {0}:{1}'.format(k, v)) else:     print('[!] Request Failed') 

Chạy tập lệnh này và bạn sẽ nhận được phản hồi cho bạn biết rằng khóa mới của bạn đã được thêm vào.

  • python add_ssh_key.py

Đầu ra sẽ giống như sau:

Output
Your key was added: ssh_key:{'id': 9458326, 'name': 'tutorial_key', 'fingerprint': '64:76:37:77:c8:c7:26:05:f5:7b:6b:e1:bb:d6:80:da', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'}

Nếu bạn quên thay đổi điều kiện “thành công” để tìm kiếm HTTP 201 thay vì 200 , bạn sẽ thấy lỗi được báo cáo, nhưng khóa sẽ vẫn được thêm vào. Xử lý lỗi của bạn sẽ cho bạn biết rằng mã trạng thái là 201 . Bạn nên công nhận điều đó với quyền là thành viên của chuỗi 200 , điều này cho thấy sự thành công. Đây là một ví dụ về cách xử lý lỗi cơ bản có thể đơn giản hóa việc khắc phục sự cố.

Khi bạn đã thêm thành công khóa bằng tập lệnh này, hãy chạy lại để xem điều gì sẽ xảy ra khi bạn cố gắng thêm một khóa đã có.

API sẽ gửi lại phản hồi HTTP 422 , tập lệnh của bạn sẽ chuyển thành thông báo “Khóa SSH đã được sử dụng trên account của bạn.”:

Output
[!] [422] Bad Request {'name': 'tutorial_key', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'} b'{"id":"unprocessable_entity","message":"SSH Key is already in use on your account"}' [!] Request Failed

Bây giờ hãy chạy lại tập lệnh get_ssh_keys.py và bạn sẽ thấy khóa mới được thêm vào danh sách.

Với những sửa đổi nhỏ, hai tập lệnh này có thể là một cách nhanh chóng để thêm SSH key mới vào account DigitalOcean của bạn khi nào bạn cần. Các chức năng liên quan trong API này cho phép bạn đổi tên hoặc xóa một khóa cụ thể bằng cách sử dụng dấu fingerprint hoặc ID khóa duy nhất của nó.

Hãy xem xét một API khác và xem các kỹ năng bạn vừa học được dịch như thế nào.

Bước 4 - Làm việc với một API khác

GitHub cũng có một API. Mọi thứ bạn đã học về cách sử dụng API DigitalOcean đều có thể áp dụng trực tiếp cho việc sử dụng API GitHub.

Làm quen với API GitHub giống như cách bạn đã làm với DigitalOcean. Tìm kiếm tài liệu API và đọc lướt phần Tổng quan . Bạn sẽ thấy ngay rằng API GitHub và API DigitalOcean có một số điểm tương đồng.

Đầu tiên, bạn sẽ nhận thấy rằng có một root chung cho tất cả các URL API: https://api.github.com/ . Bạn biết cách sử dụng biến đó như một biến trong mã của bạn để sắp xếp hợp lý và giảm khả năng xảy ra lỗi.

API của GitHub sử dụng JSON làm định dạng yêu cầu và phản hồi, giống như DigitalOcean, vì vậy bạn biết cách thực hiện các yêu cầu đó và xử lý phản hồi.

Phản hồi bao gồm thông tin về giới hạn tốc độ trong tiêu đề phản hồi HTTP, sử dụng các tên gần như giống nhau và chính xác các giá trị giống như DigitalOcean.

GitHub sử dụng OAuth để xác thực và bạn có thể gửi mã thông báo của bạn trong tiêu đề yêu cầu. Các chi tiết của mã thông báo đó hơi khác một chút, nhưng cách nó được sử dụng giống với cách bạn đã thực hiện với API của DigitalOcean.

Cũng có một số khác biệt. GitHub khuyến khích sử dụng tiêu đề yêu cầu để cho biết version API bạn muốn sử dụng. Bạn biết cách thêm tiêu đề vào các yêu cầu trong Python.

GitHub cũng muốn bạn sử dụng một chuỗi User-Agent duy nhất trong các yêu cầu, để họ có thể tìm thấy bạn dễ dàng hơn nếu mã của bạn đang gây ra sự cố. Bạn cũng sẽ xử lý điều này với một tiêu đề.

API GitHub sử dụng các phương thức yêu cầu HTTP tương tự, nhưng cũng sử dụng một phương thức mới gọi là PATCH cho các hoạt động nhất định. API GitHub sử dụng GET để đọc thông tin, POST để thêm một mục mới và PATCH để sửa đổi một mục hiện có. Yêu cầu PATCH này là loại yêu cầu bạn cần để ý trong tài liệu API.

Không phải tất cả các lệnh gọi API GitHub đều yêu cầu xác thực. Ví dụ: bạn có thể lấy danh sách kho của user mà không cần mã thông báo truy cập. Hãy tạo một script để thực hiện yêu cầu đó và hiển thị kết quả.

Ta sẽ đơn giản hóa việc xử lý lỗi trong tập lệnh này và chỉ sử dụng một câu lệnh để xử lý tất cả các lỗi có thể xảy ra. Không phải lúc nào bạn cũng cần mã để xử lý từng loại lỗi riêng biệt, nhưng bạn nên làm điều gì đó với các điều kiện lỗi, nếu chỉ để nhắc nhở bản thân rằng mọi thứ không phải lúc nào cũng đi theo cách bạn muốn .

Tạo một file mới có tên github_list_repos.py trong editor và thêm nội dung sau, nội dung này trông khá quen thuộc:

github_list_repos.py
import json import requests   api_url_base = 'https://api.github.com/' headers = {'Content-Type': 'application/json',            'User-Agent': 'Python Student',            'Accept': 'application/vnd.github.v3+json'}  

Hàng nhập khẩu giống như hàng ta đang sử dụng. api_url_base là nơi bắt đầu tất cả các API GitHub.

Các tiêu đề bao gồm hai trong số các tiêu đề tùy chọn mà GitHub đề cập trong phần tổng quan của chúng, cộng với một tiêu đề cho biết ta đang gửi dữ liệu có định dạng JSON theo yêu cầu của ta .

Mặc dù đây là một tập lệnh nhỏ, ta vẫn sẽ xác định một hàm để giữ logic của ta theo module và đóng gói logic để thực hiện yêu cầu. Thông thường, các tập lệnh nhỏ của bạn sẽ phát triển thành các tập lệnh lớn hơn, vì vậy sẽ rất hữu ích nếu bạn cần chăm chỉ về điều này. Thêm một hàm có tên get_repos chấp nhận tên user làm đối số của nó:

github_list_repos.py
 ... def get_repos(username):      api_url = '{}orgs/{}/repos'.format(api_url_base, username)      response = requests.get(api_url, headers=headers)      if response.status_code == 200:         return (response.content)     else:         print('[!] HTTP {0} calling [{1}]'.format(response.status_code, api_url))         return None  

Bên trong hàm, ta tạo URL từ api_url_base , tên của user mà ta quan tâm và các phần tĩnh của URL cho GitHub biết ta muốn danh sách repository . Sau đó, ta kiểm tra Mã trạng thái HTTP của phản hồi đảm bảo rằng nó là 200 (thành công). Nếu thành công, ta gửi lại nội dung phản hồi. Nếu không, thì ta in ra Mã trạng thái thực và URL mà ta đã tạo để ta có ý tưởng về nơi ta có thể đã sai.

Bây giờ, hãy gọi hàm và nhập tên user GitHub mà bạn muốn sử dụng. Ta sẽ sử dụng octokit cho ví dụ này. Sau đó in kết quả ra màn hình:

github_list_repos.py
 ... repo_list = get_repos('octokit')  if repo_list is not None:     print(repo_list) else:     print('No Repo List Found') 

Lưu file và chạy tập lệnh để xem các repository cho user bạn đã chỉ định.

  • python github_list_repos.py

Bạn sẽ thấy nhiều dữ liệu trong kết quả vì ta chưa phân tích cú pháp phản hồi dưới dạng JSON trong ví dụ này, cũng như chưa lọc kết quả thành các khóa cụ thể. Sử dụng những gì bạn đã học trong các tập lệnh khác để làm điều đó. Nhìn vào kết quả bạn nhận được và xem liệu bạn có thể in ra tên repository hay không.

Một điều thú vị về các API GitHub này là bạn có thể truy cập các yêu cầu mà bạn không cần xác thực trực tiếp trong trình duyệt web của bạn , Điều này cho phép bạn so sánh các phản hồi với những gì bạn thấy trong tập lệnh của bạn . Hãy thử truy cập https://api.github.com/orgs/octokit/repos trong trình duyệt của bạn để xem phản hồi ở đó.

Bây giờ, bạn đã biết cách đọc tài liệu và viết mã cần thiết để gửi các yêu cầu cụ thể hơn nhằm hỗ trợ các mục tiêu của bạn với API GitHub.

Bạn có thể tìm thấy mã hoàn chỉnh cho tất cả các ví dụ trong hướng dẫn này trong kho lưu trữ này trên GitHub .

Kết luận

Trong hướng dẫn này, bạn đã học cách sử dụng API web cho hai dịch vụ khác nhau với phong cách hơi khác nhau. Bạn đã thấy tầm quan trọng của việc bao gồm mã xử lý lỗi để giúp gỡ lỗi dễ dàng hơn và các tập lệnh mạnh mẽ hơn. Bạn đã sử dụng các requests module Python và json để cách ly bạn khỏi các chi tiết của các công nghệ đó và chỉ cần hoàn thành công việc của bạn và bạn đã gói gọn quá trình xử lý yêu cầu và phản hồi trong một hàm để làm cho các tập lệnh của bạn có tính module hơn.

Và hơn thế nữa, bây giờ bạn có một quy trình lặp lại để làm theo khi học bất kỳ API web mới nào:

  1. Tìm tài liệu và đọc phần giới thiệu để hiểu các nguyên tắc cơ bản về cách tương tác với API.
  2. Nhận mã xác thực nếu bạn cần và viết một tập lệnh module với xử lý lỗi cơ bản để gửi một yêu cầu đơn giản, phản hồi lỗi và xử lý phản hồi.
  3. Tạo các yêu cầu sẽ giúp bạn có được thông tin mà bạn muốn từ dịch vụ.

Bây giờ, hãy củng cố kiến thức mới thu được này và tìm một API khác để sử dụng hoặc thậm chí là một tính năng khác của một trong các API bạn đã sử dụng ở đây. Một dự án của bạn sẽ giúp củng cố những gì bạn đã học ở đây.


Tags:

Các tin liên quan

Cách thu thập thông tin một trang web với Scrapy và Python 3
2019-03-20
Cách cạo các trang web với Beautiful Soup và Python 3
2019-03-20
Tạo ứng dụng web tiến bộ (PWA) với React
2019-03-02
Tụ điện: Chạy ứng dụng web trên thiết bị di động
2019-02-27
Cách gửi thông báo đẩy web từ ứng dụng Django
2018-10-24
Cách xây dựng ứng dụng web hiện đại để quản lý thông tin khách hàng với Django và React trên Ubuntu 18.04
2018-10-22
Cách cài đặt Django Web Framework trên Ubuntu 18.04
2018-08-06
Cách sử dụng Trình quản lý cảnh báo và Trình xuất hộp đen để giám sát web server của bạn trên Ubuntu 16.04
2018-05-11
Giải pháp Deep Dive: Xây dựng một ứng dụng web khả dụng cao với khả năng xử lý và lưu trữ web bằng cách sử dụng MongoDB và Elk Stack
2018-03-15
Các bước đầu tiên của bạn với API âm thanh web
2018-01-09