前書き
API、またはApplicationProgramInterfaceを使用すると、開発者は1つのアプリを別のアプリと統合できます。 プログラムの内部動作の一部を限定的な方法で公開します。
APIを使用して、他のプログラムから情報を取得したり、Webブラウザーで通常行うことを自動化することができます。 APIを使用して、他の方法ではできないことを実行できる場合があります。 驚くべき数のWebプロパティが、Twitter、Facebook、GitHub、DigitalOceanなど、より馴染みのあるWebサイトまたはモバイルアプリとともにWebベースのAPIを提供しています。
how to code in Python 3に関するいくつかのチュートリアルを完了し、Pythonの構文、構造、およびいくつかの組み込みfunctionsに慣れている場合は、お気に入りを利用するPythonプログラムを作成できます。 API。
このガイドでは、PythonをDigitalOcean APIで使用して、DigitalOceanアカウントに関する情報を取得する方法を学習します。 次に、学習した内容をGitHub’s APIに適用する方法を見ていきます。
完了したら、Web APIに共通の概念を理解し、他のサービスからAPIを試すために使用できるステップバイステップのプロセスと実際のコードサンプルが得られます。
前提条件
このガイドを始める前に、次のものが必要です。
-
Python 3のローカル開発環境。 How To Install and Set Up a Local Programming Environment for Python 3に従って、必要なすべてを構成できます。
-
使いやすいテキストエディタ。 お気に入りがまだない場合は、構文を強調表示したものを選択してください。 Windowsの場合はNotepad++、macOSの場合はBBEdit、任意のプラットフォームの場合はSublime TextまたはAtomがすべて適切な選択です。
-
DigitalOceanアカウントとAPIキー。 How To Use the DigitalOcean API v2の最初の数段落は、これを行う方法を示しています。
[[step-1 -—- getting-familiar-with-an-api]] ==ステップ1—APIに精通する
新しいAPIを使用するための最初のステップは、ドキュメントを見つけて、ベアリングを取得することです。 DigitalOcean APIのドキュメントはhttps://developers.digitalocean.com/から始まります。 他のサービスのAPIを見つけるには、サイトの名前と「API」を検索します。すべてのサービスがフロントページでそれらを宣伝するわけではありません。
一部のサービスにはAPI wrappersがあります。 APIラッパーは、選択したプログラミング言語でAPIを使いやすくするためにシステムにインストールするコードです。 このガイドでは、APIの内部動作の多くを隠し、多くの場合APIが実行できるすべてを公開しないため、ラッパーを使用しません。 ラッパーは、何かを迅速に完了させたい場合に最適ですが、API自体ができることをしっかりと理解することは、ラッパーが目的に合っているかどうかを判断するのに役立ちます。
まず、https://developers.digitalocean.com/documentation/v2/にあるDigitalOcean APIの概要を見て、要求の送信方法と応答で何を期待するかについての基本のみを理解するようにしてください。 この時点では、次の3つだけを学習しようとしています。
-
リクエストはどのようなものですか? それらはすべてURLだけですか? より詳細なリクエストの場合、データはどのようにフォーマットされますか? 通常、これはWebブラウザが使用するようなJSONまたはクエリ文字列パラメータですが、XMLまたはカスタム形式を使用するものもあります。
-
応答はどのように見えますか? APIドキュメントには、リクエストとレスポンスのサンプルが表示されます。 JSON、XML、またはその他の種類の応答を取得しますか?
-
要求または応答ヘッダーには何が入りますか? 多くの場合、要求ヘッダーには認証トークンが含まれ、応答ヘッダーには、レート制限にどれだけ近いかなど、サービスの使用に関する現在の情報が提供されます。
DigitalOcean APIは、HTTPmethods(verbsと呼ばれることもあります)を使用して、既存の情報を読み取ろうとしているのか、新しい情報を作成しようとしているのか、何かを削除しようとしているのかを示します。 ドキュメントのこの部分では、使用されるメソッドと目的を説明します。 一般に、GETリクエストはPOSTよりも簡単ですが、ここで作業を終える頃には、それほど大きな違いはありません。
APIドキュメントの次のセクションでは、サーバーがリクエストにどのように応答するかについて説明します。 一般に、リクエストは成功するか失敗します。 失敗した場合、原因はリクエストに問題があるか、サーバー上の問題です。 この情報はすべて、カテゴリに分類された3桁の数字であるHTTP status codesを使用して伝達されます。
-
200
シリーズは「成功」を意味します—要求は有効であり、応答は論理的にそれに続くものです。 -
400
シリーズは、「不正な要求」を意味します—要求に問題があったため、サーバーは要求どおりに処理しませんでした。 HTTP400
レベルのエラーの一般的な原因は、フォーマットが不適切な要求と認証の問題です。 -
500
シリーズは、「サーバーエラー」を意味します。リクエストは問題ない可能性がありますが、サーバーは、制御できない理由により、現在、適切な応答を提供できませんでした。 これらはまれなはずですが、コードでそれらを処理できるように、可能性を認識する必要があります。
コードは、HTTPステータスコードを使用して何かを実行する前に、常にHTTPステータスコードをチェックする必要があります。 これを行わないと、不完全な情報でトラブルシューティングに時間を浪費することになります。
リクエストを送信する方法と、レスポンスで何を検索するかについての一般的な考えができたので、最初のリクエストを送信します。
[[step-2 -—- getting-information-from-the-web-api]] ==ステップ2— WebAPIから情報を取得する
DigitalOceanアカウントには、Web UIには表示されていない管理情報が含まれています。 APIは、馴染みのある情報の異なるビューを提供できます。 この別のビューを見るだけで、APIで何をしたいのかというアイデアが浮かんだり、知らなかったサービスやオプションが明らかになったりすることがあります。
スクリプト用のプロジェクトを作成することから始めましょう。 apis
というプロジェクトの新しいディレクトリを作成します。
mkdir apis
次に、この新しいディレクトリに移動します。
cd apis
このプロジェクトの新しいvirtualenvを作成します。
python3 -m venv apis
virtualenvを起動します。
source apis/bin/activate
次に、requestsライブラリをインストールします。これをスクリプトで使用して、スクリプトでHTTPリクエストを作成します。
pip install requests
環境を構成した状態で、do_get_account.py
という名前の新しいPythonファイルを作成し、テキストエディターで開きます。 JSONおよびHTTPリクエストを処理するために、このプログラムをimporting librariesで開始します。
do_get_account.py
import json
import requests
これらのimport
ステートメントは、JSONデータ形式とHTTPプロトコルを操作できるようにするPythonコードをロードします。 これらのライブラリを使用しているのは、HTTPリクエストを送信する方法や、有効なJSONを解析および作成する方法の詳細に関心がないためです。これらを使用してこれらのタスクを実行したいだけです。 このチュートリアルのスクリプトはすべて、このように始まります。
次に、すべてのリクエストで同じ情報を保持するために、いくつかのvariablesを設定します。 これにより、何度も何度も入力する必要がなくなり、何か変更があった場合に更新を行うための単一の場所が得られます。 import
ステートメントの後に、これらの行をファイルに追加します。
do_get_account.py
...
api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'
api_token
変数は、DigitalOceanAPIトークンを保持する文字列です。 例の値を独自のトークンに置き換えます。 api_url_base
変数は、DigitalOceanAPIのすべてのURLで始まる文字列です。 コードの後半で必要に応じて追加します。
次に、APIドキュメントで説明されている方法でHTTPリクエストヘッダーを設定する必要があります。 これらの行をファイルに追加して、リクエストヘッダーを含むdictionaryを設定します。
do_get_account.py
...
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer {0}'.format(api_token)}
これにより、2つのヘッダーが同時に設定されます。 Content-Type
ヘッダーは、リクエストの本文にJSON形式のデータを期待するようにサーバーに指示します。 Authorization
ヘッダーにはトークンを含める必要があるため、Pythonの文字列フォーマットロジックを使用して、文字列を作成するときにapi_token
変数を文字列に挿入します。 トークンをリテラル文字列としてここに入れることもできますが、これを分離することで、今後いくつかのことが容易になります。
-
トークンを置き換える必要がある場合は、別の変数を使用すると、どこでそれを行うかを簡単に確認できます。
-
コードを誰かと共有したい場合は、APIトークンを削除するのが簡単になり、友人がコードを置く場所を簡単に確認できます。
-
自己文書化されています。 APIトークンが文字列リテラルとしてのみ使用される場合、コードを読んでいる人は自分が見ているものを理解できない可能性があります。
これらのセットアップの詳細が網羅されたので、実際にリクエストを送信します。 リクエストの作成と送信を開始したいかもしれませんが、もっと良い方法があります。 このロジックをリクエストの送信とレスポンスの読み取りを処理する関数に配置する場合、何をしているのかをもう少し明確に考える必要があります。 また、テストと再利用をより簡単にするコードになります。 それが私たちがやろうとしていることです。
この関数は、作成した変数を使用してリクエストを送信し、Python辞書でアカウント情報を返します。
この初期段階でロジックを明確にするため、詳細なエラー処理はまだ行いませんが、すぐに追加します。
アカウント情報を取得する関数を定義します。 関数の機能にちなんで名前を付けることをお勧めします。これはアカウント情報を取得するため、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
ヘッダーで使用したのと同様のPythonの文字列フォーマット方法を使用して、api_url
の値を作成します。文字列account
の前にAPIのベースURLを追加して、アカウント情報を返すURLであるURLhttps://api.digitalocean.com/v2/account
を取得します。
response
変数は、Pythonrequests
moduleによって作成されたオブジェクトを保持します。 この行は、スクリプトの開始時に定義したヘッダーを使用して作成したURLに要求を送信し、APIから応答を返します。
次に、レスポンスのHTTPステータスコードを確認します。
成功した応答である200
の場合、json
モジュールのloads
関数を使用して文字列をJSONとしてロードします。 ロードする文字列は、response
オブジェクトresponse.content
のコンテンツです。 .decode('utf-8')
の部分は、DigitalOcean APIからのすべての応答がそうであるように、このコンテンツがUTF-8文字セットを使用してエンコードされていることをPythonに通知します。 json
モジュールは、そのオブジェクトからオブジェクトを作成します。これをこの関数の戻り値として使用します。
応答がnot200
の場合、None
を返します。これは、この関数を呼び出すときに確認できるPythonの特別な値です。 この時点でエラーを無視していることに気付くでしょう。 これは、「成功」ロジックを明確に保つためです。 より包括的なエラーチェックを近日中に追加します。
次に、この関数を呼び出して、適切な応答が得られたことを確認し、APIが返した詳細を出力します。
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()
は、account_info
変数をget_account_info()
の呼び出しから戻ってきたものに設定するため、特別な値None
になるか、またはに関する情報のコレクションになります。アカウント。
None
でない場合は、すべてのPython辞書にあるitems()
メソッドを使用して、各情報を独自の行に出力します。
それ以外の場合(つまり、account_info
がNone
の場合)、エラーメッセージが出力されます。
ここでちょっと休みましょう。 二重否定を含むこのif
ステートメントは、最初は扱いにくいと感じるかもしれませんが、これは一般的なPythonイディオムです。 その長所は、エラーケースを処理した後ではなく、成功時に実行されるコードをconditionalに非常に近く保つことです。
必要に応じて別の方法で行うこともできますが、実際にそのコードを自分で記述するのは良い練習になるかもしれません。 if account_info is not None:
の代わりに、if account_info is None:
から始めて、残りがどのように配置されるかを確認できます。
スクリプトを保存して試してください:
python do_get_account.py
出力は次のようになります。
OutputHere's your info:
droplet_limit:25
email:[email protected]
status:active
floating_ip_limit:3
email_verified:True
uuid:123e4567e89b12d3a456426655440000
status_message:
これで、APIからデータを取得する方法がわかりました。 次に、APIを使用してデータを変更する、もう少し興味深いものに進みます。
[[step-3 -—- modifying-information-on-the-server]] ==ステップ3—サーバー上の情報の変更
読み取り専用リクエストで練習したら、変更を開始します。 PythonとDigitalOcean APIを使用して、SSHキーをDigitalOceanアカウントに追加して、これを調べてみましょう。
まず、https://developers.digitalocean.com/documentation/v2/#ssh-keysで入手できるSSHキーのAPIドキュメントを見てください。
APIを使用すると、アカウントの現在のSSHキーを一覧表示したり、新しいキーを追加したりできます。 SSHキーのリストを取得するリクエストは、アカウント情報を取得するリクエストとよく似ています。 ただし、応答は異なります。アカウントとは異なり、0、1、または多くのSSHキーを持つことができます。
このスクリプト用にdo_ssh_keys.py
という名前の新しいファイルを作成し、最後のファイルとまったく同じように開始します。 json
およびrequests
モジュールをインポートして、JSONまたはHTTPプロトコルの詳細について心配する必要がないようにします。 次に、DigitalOcean APIトークンを変数として追加し、辞書にリクエストヘッダーを設定します。
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)}
SSHキーを取得するために作成する関数は、アカウント情報を取得するために使用した関数と似ていますが、今回はエラーをより直接処理します。
まず、API呼び出しを行い、応答をresponse
応答変数に格納します。 ただし、api_url
は前のスクリプトと同じではありません。今回はhttps://api.digitalocean.com/v2/account/keys
を指す必要があります。
このコードをスクリプトに追加します。
do_ssh_keys.py
...
def get_ssh_keys():
api_url = '{0}account/keys'.format(api_url_base)
response = requests.get(api_url, headers=headers)
次に、応答のHTTPステータスコードを見て、エラー処理を追加します。 200
の場合、以前と同じように、応答の内容を辞書として返します。 それ以外の場合は、ステータスコードの種類に関連する有用なエラーメッセージを出力してから、None
を返します。
次の行を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
このコードは、応答内のHTTPステータスコードを調べることにより、6つの異なるエラー状態を処理します。
-
500
以上のコードは、サーバーに問題があることを示します。 これらはまれであり、リクエストの問題が原因ではないため、ステータスコードのみを出力します。 -
404
のコードは「見つかりません」を意味します。これは、おそらくURLのタイプミスに起因します。 このエラーについては、ステータスコードとその原因となったURLを出力するため、失敗の理由を確認できます。 -
401
のコードは、認証が失敗したことを意味します。 これの最も可能性の高い原因は、api_key
が正しくないか欠落していることです。 -
300
の範囲のコードは、リダイレクトを示します。 DigitalOcean APIはリダイレクトを使用しないため、これは決して発生しませんが、エラーを処理している間は確認するのに問題はありません。 多くのバグは、プログラマーが決して発生してはならないと考えたことによって引き起こされます。 -
200
のコードは、要求が正常に処理されたことを意味します。 このため、何も印刷しません。 前のスクリプトで使用したのと同じ構文を使用して、sshキーをJSONオブジェクトとして返すだけです。 -
応答コードがそれ以外の場合、ステータスコードを「予期しないエラー」として出力します。
これで、APIの呼び出しで発生する可能性のあるエラーを処理できます。 この時点で、エラーメッセージとNone
オブジェクトがあるか、成功して0個以上のSSHキーを含むJSONオブジェクトがあります。 次のステップは、それらを印刷することです。
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')
応答にはSSHキーのlist(または配列)が含まれているため、すべてのキーを表示するためにリスト全体を反復処理する必要があります。 これにはPythonのenumerate
メソッドを使用します。 これは、辞書で使用できるitems
メソッドに似ていますが、代わりにリストで機能します。
for
loopだけでなく、enumerate
を使用します。これは、特定のキーについて、リストのどこまで進んでいるかを確認できるようにするためです。
各キーの情報はディクショナリとして返されるため、前のスクリプトのアカウント情報ディクショナリで使用したのと同じfor k,v in details.items():
コードを使用します。
このスクリプトを実行すると、アカウントに既に存在するSSHキーのリストが表示されます。
python get_ssh_keys.py
アカウントにすでにあるSSHキーの数に応じて、出力は次のようになります。
OutputHere 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
アカウントのSSHキーをリストできるようになったので、ここでの最後のスクリプトは、リストに新しいキーを追加するスクリプトになります。
新しいSSHキーを追加する前に、キーを生成する必要があります。 このステップのより完全な取り扱いについては、チュートリアルHow to Set Up SSH Keysをご覧ください。
ただし、この目的のためには、単純なキーが必要です。 このコマンドを実行して、Linux、BSD、またはMacOSで新しいコマンドを生成します。 必要に応じて、既存のドロップレットでこれを実行できます。
ssh-keygen -t rsa
プロンプトが表示されたら、ファイルを入力してキーを保存し、パスフレーズを提供しません。
OutputGenerating 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.
...
公開鍵ファイルはスクリプトに必要になるため、保存場所をメモしてください。
新しいPythonスクリプトを開始し、それをadd_ssh_key.py
と呼び、他のスクリプトと同じように開始します。
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)}
関数を使用してリクエストを行いますが、これは少し異なります。
2つの引数を受け入れるadd_ssh_key
という関数を作成します。新しいSSHキーに使用する名前と、ローカルシステム上のキー自体のファイル名です。 この関数はread the fileを実行し、GET
の代わりにHTTPPOST
要求を行います。
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)
行with open(filename, 'r') as f:
はファイルを読み取り専用モードで開き、次の行はファイルから最初の(そして唯一の)行を読み取り、それをssh_key
変数に格納します。
次に、APIが期待する名前と値を使用してssh_key
というPython辞書を作成します。
ただし、リクエストを送信すると、もう少し新しいものがあります。 これはGET
ではなくPOST
であり、JSONとしてエンコードされたPOST
リクエストの本文でssh_key
を送信する必要があります。 requests
モジュールが詳細を処理します。 requests.post
は、POST
メソッドを使用するように指示し、json=ssh_key
を含めると、JSONとしてエンコードされたssh_key
変数をリクエストの本文に送信するように指示します。
APIによると、応答は成功すると200
ではなくHTTP201
になり、応答の本文には追加したばかりのキーの詳細が含まれます。
次のエラー処理コードをadd_ssh_key
関数に追加します。 前のスクリプトと似ていますが、今回は成功するために200
ではなくコード201
を探す必要があります。
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
この関数は、前の関数と同様に、None
または応答コンテンツのいずれかを返すため、前と同じアプローチを使用して結果を確認します。
次に、関数を呼び出して結果を処理します。 2番目の引数として、新しく作成したSSHキーへのパスを渡します。
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')
このスクリプトを実行すると、新しいキーが追加されたことを知らせる応答が返されます。
python add_ssh_key.py
出力は次のようになります。
OutputYour 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'}
「成功」条件を変更して200
ではなくHTTP201
を検索するのを忘れた場合、エラーが報告されますが、キーはまだ追加されています。 エラー処理により、ステータスコードは201
であることがわかります。 成功を示す200
シリーズのメンバーとしてそれを認識する必要があります。 これは、基本的なエラー処理がトラブルシューティングを簡単にする方法の例です。
このスクリプトでキーを正常に追加したら、もう一度実行して、既に存在するキーを追加しようとしたときに何が起こるかを確認します。
APIはHTTP422
応答を送り返します。これは、スクリプトが「SSHキーは既にアカウントで使用されています」というメッセージに変換されます。
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
ここで、get_ssh_keys.py
スクリプトを再度実行すると、新しく追加されたキーがリストに表示されます。
わずかな変更を加えるだけで、これら2つのスクリプトを使用して、必要なときにいつでも新しいSSHキーをDigitalOceanアカウントに追加できます。 このAPIの関連関数を使用すると、一意のキーIDまたはフィンガープリントを使用して、特定のキーの名前を変更または削除できます。
別のAPIを見て、今学んだスキルがどのように翻訳されるかを見てみましょう。
[[step-4 -—- working-with-a-different-api]] ==ステップ4—別のAPIでの作業
GitHubにはAPIもあります。 DigitalOcean APIの使用について学んだことはすべて、GitHub APIの使用に直接適用できます。
DigitalOceanで行ったのと同じ方法でGitHub APIを理解してください。 API documentationを検索し、Overviewセクションをスキミングします。 GitHub APIとDigitalOcean APIにはいくつかの類似点があることがすぐにわかります。
まず、すべてのAPI URLに共通のルートhttps://api.github.com/
があることに気付くでしょう。 これをコード内の変数として使用して、エラーの可能性を合理化し、減らす方法を知っています。
GitHubのAPIは、DigitalOceanと同じようにJSONをリクエストおよびレスポンスの形式として使用しているため、これらのリクエストの作成方法とレスポンスの処理方法を知っています。
応答には、DigitalOceanとほぼ同じ名前とまったく同じ値を使用して、HTTP応答ヘッダーにレート制限に関する情報が含まれます。
GitHubは認証にOAuthを使用し、リクエストヘッダーでトークンを送信できます。 このトークンの詳細は少し異なりますが、使用方法はDigitalOceanのAPIで行った方法と同じです。
いくつかの違いもあります。 GitHubでは、使用するAPIのバージョンを示すリクエストヘッダーの使用を推奨しています。 Pythonでリクエストにヘッダーを追加する方法を知っています。
また、GitHubでは、リクエストで一意のUser-Agent
文字列を使用する必要があるため、コードが問題を引き起こしている場合に、より簡単にユーザーを見つけることができます。 これもヘッダーで処理します。
GitHub APIは同じHTTPリクエストメソッドを使用しますが、特定の操作にはPATCH
という新しいメソッドも使用します。 GitHub APIは、GET
を使用して情報を読み取り、POST
を使用して新しいアイテムを追加し、PATCH
を使用して既存のアイテムを変更します。 このPATCH
リクエストは、APIドキュメントで注目したい種類のものです。
すべてのGitHub API呼び出しが認証を必要とするわけではありません。 たとえば、アクセストークンを必要とせずに、ユーザーのリポジトリのリストを取得できます。 そのリクエストを行い、結果を表示するスクリプトを作成しましょう。
このスクリプトのエラー処理を簡素化し、1つのステートメントのみを使用して、考えられるすべてのエラーを処理します。 さまざまな種類のエラーを個別に処理するためにコードが常に必要なわけではありませんが、エラー状態で何かをするのは良いことです。
エディタでgithub_list_repos.py
という名前の新しいファイルを作成し、次のコンテンツを追加します。これはかなり見覚えがあるはずです。
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'}
インポートは、これまで使用してきたものと同じです。 api_url_base
は、すべてのGitHubAPIが始まる場所です。
ヘッダーには、GitHubが概要で言及しているオプションの2つに加えて、リクエストでJSON形式のデータを送信しているというヘッダーが含まれています。
これは小さなスクリプトですが、ロジックをモジュール化してリクエストを行うためのロジックをカプセル化するために、関数を定義します。 多くの場合、小さなスクリプトはより大きなスクリプトに成長するため、これについて熱心に取り組むと役に立ちます。 ユーザー名を引数として受け入れるget_repos
という関数を追加します。
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
関数内では、api_url_base
、関心のあるユーザーの名前、およびGitHubにリポジトリリストが必要であることを通知するURLの静的部分からURLを作成します。 次に、応答のHTTPステータスコードをチェックして、200
(成功)であることを確認します。 成功した場合、応答コンテンツを返します。 そうでない場合は、実際のステータスコードと作成したURLを出力します。これにより、どこが間違っているのかがわかります。
次に、関数を呼び出して、使用するGitHubユーザー名を渡します。 この例ではoctokit
を使用します。 次に、結果を画面に印刷します。
github_list_repos.py
...
repo_list = get_repos('octokit')
if repo_list is not None:
print(repo_list)
else:
print('No Repo List Found')
ファイルを保存し、スクリプトを実行して、指定したユーザーのリポジトリを表示します。
python github_list_repos.py
この例では応答をJSONとして解析しておらず、結果を特定のキーにフィルター処理していないため、出力には多くのデータが表示されます。 他のスクリプトで学んだことを使用してそれを行います。 取得した結果を見て、リポジトリ名を印刷できるかどうかを確認します。
これらのGitHub APIの便利な点は、認証が不要なリクエストにWebブラウザーで直接アクセスできることです。これにより、スクリプトで表示されるものとレスポンスを比較できます。 ブラウザでhttps://api.github.com/orgs/octokit/reposにアクセスして、そこでの応答を確認してください。
これで、GitHub APIを使用して独自の目標をサポートするために、ドキュメントを読み、より具体的なリクエストを送信するために必要なコードを記述する方法を理解できました。
このチュートリアルのすべての例の完成したコードは、this repository on GitHubにあります。
結論
このチュートリアルでは、スタイルがわずかに異なる2つの異なるサービスでWeb APIを使用する方法を学びました。 デバッグを容易にし、スクリプトをより堅牢にするために、エラー処理コードを含めることの重要性を見てきました。 Pythonモジュールrequests
とjson
を使用して、これらのテクノロジーの詳細からユーザーを隔離し、作業を完了し、要求と応答の処理を関数にカプセル化して、スクリプトをよりモジュール化しました。
さらに、新しいWeb APIを学習する際に従うべき反復可能なプロセスがあります。
-
APIを操作する方法の基礎を理解するには、ドキュメントを見つけて概要を読んでください。
-
必要に応じて認証トークンを取得し、基本的なエラー処理を備えたモジュラースクリプトを記述して、単純なリクエストを送信し、エラーに応答し、応答を処理します。
-
サービスから必要な情報を取得するリクエストを作成します。
ここで、この新たに得られた知識を固め、使用する別のAPI、またはここで使用したAPIの別の機能を見つけます。 独自のプロジェクトは、ここで学んだことを固めるのに役立ちます。