Cisco Japan Blog の SDN カテゴリー に「Python を使って APIC-EM の REST API にアクセスする」という記事が掲載されています。
(APIC-EM に限らず) Python や Ruby から REST API にアクセスするサンプルはしばしば見かけるのですが、C# のサンプルはなぜか数が少ないきがします… (探し方が悪い?)。というわけで C# のサンプルを書いてみました。あくまでサンプルなのでエラー処理はしていません。
処理の大まかな流れ
実際に何がしかの REST API を利用する前に「ServiceTicket」と呼ばれる資格情報を取得する必要があります。よって、大まかな処理順序は以下のようになります。
- 適切な ID/Password を使って ServiceTicket を取得する
- 取得出来た ServiceTicket を使って必要な REST API を呼び出す
サンプルコード
やや長いですが、今回のサンプルコード全体は以下の通りです。
using System; using System.Net; using System.Runtime.Serialization; using RestSharp; namespace RestApiSample { class LoginInfo { public string username { get; set; } public string password { get; set; } public LoginInfo(string _username, string _password) { username = _username; password = _password; } } [DataContract] class ServiceTicket { [DataMember] public ServiceTicketResponse response { get; set; } [DataMember] public float version { get; set; } } [DataContract] class ServiceTicketResponse { [DataMember] public string serviceTicket { get; set; } [DataMember] public uint idleTimeout { get; set; } [DataMember] public uint sessionTimeout { get; set; } } [DataContract] class NetworkDeviceCount { [DataMember] public uint response { get; set; } public float version { get; set; } } class Program { static void Main(string[] args) { // Ignore self-signed SSL certificate warnings. ServicePointManager.ServerCertificateValidationCallback += ( sender, certificate, chain, sslPolicyErrors) => true; string baseUrl = "https://10.0.0.1"; string username = "admin"; string password = "password"; // Get Service Ticket. string serviceTicket = GetServiceTicket(baseUrl, username, password); // Get network device count. NetworkDeviceCount networkDeviceCount = GetNetworkDevivceCount(baseUrl, serviceTicket); Console.WriteLine(networkDeviceCount.response); } static string GetServiceTicket(string _baseUrl, string _username, string _password) { var client = new RestClient(_baseUrl); LoginInfo loginInfo = new LoginInfo(_username, _password); var request = new RestRequest("api/v1/ticket", Method.POST); request.RequestFormat = DataFormat.Json; request.AddBody(loginInfo); IRestResponse response = client.Execute(request); RestSharp.Deserializers.JsonDeserializer deserializer = new RestSharp.Deserializers.JsonDeserializer(); var serviceTicket = deserializer.Deserialize<ServiceTicket>(response).response; return serviceTicket.serviceTicket; } static NetworkDeviceCount GetNetworkDevivceCount(string _baseUrl, string _serviceTicket) { var client = new RestClient(_baseUrl); var request = new RestRequest("api/v1/network-device/count", Method.GET); request.AddHeader("X-Auth-Token", _serviceTicket); IRestResponse response = client.Execute(request); RestSharp.Deserializers.JsonDeserializer deserializer = new RestSharp.Deserializers.JsonDeserializer(); var networkDeviceCount = deserializer.Deserialize<NetworkDeviceCount>(response); return networkDeviceCount; } } }
補足説明
RestSharp で REST API を操作する
C# で使える REST API 関連のライブラリは幾つかあるようですが、今回は RestSharp を使いました。NuGet からインストールするなり、公式サイトからダウンロードしてプロジェクトへ参照を追加するなり、用意しておきます。
サーバ証明書の警告を無視する
APIC-EM はデフォルトで自己証明書を利用していますので、(当然ですが) そのままクライアントのブラウザからアクセスすると「証明書の正当性を確認出来ない」という警告が表示されます。C# から REST API で APIC-EM にアクセスした場合はエラーとなり、処理が継続出来ません。そこで証明書の警告を無視する為に以下のコードを追加しておきます。
// Ignore self-signed SSL certificate warnings. ServicePointManager.ServerCertificateValidationCallback += ( sender, certificate, chain, sslPolicyErrors) => true;
データ構造をデータコントラクトとして定義する
Role Based Access Control の /ticket という API リファレンスを見ると Response Class は以下のように定義されています。
TicketRbacResult { version (string, optional), response (ServiceTicketRbac, optional) } ServiceTicketRbac { idleTimeout (integer, optional), serviceTicket (string): Service Ticket to be used as authentication Ticket, sessionTimeout (integer, optional) }
実際にこの REST API (/api/v1/ticket) へ適切にアクセスすると、以下のような JSON のレスポンスを得られます。
{"response":{"serviceTicket":"ST-59-u9Kxu6WzaXUUejbhfc24-cas","idleTimeout":1800,"sessionTimeout":21600},"version":"1.0"}
これをインデントすると以下のようになります。
{ "response": { "idleTimeout": 1800, "serviceTicket": "ST-59-u9Kxu6WzaXUUejbhfc24-cas", "sessionTimeout": 21600 }, "version": "1.0" }
これを C# のデータコントラクトとして表現すると以下のように書けます。適当に書いてしまったのでクラス名が API リファレンスと一致していません… orz゛
[DataContract] class ServiceTicket { [DataMember] public ServiceTicketResponse response { get; set; } [DataMember] public float version { get; set; } } [DataContract] class ServiceTicketResponse { [DataMember] public string serviceTicket { get; set; } [DataMember] public uint idleTimeout { get; set; } [DataMember] public uint sessionTimeout { get; set; } }
POST 時のリクエストボディの書き方
今回は POST する際、リクエストボディを以下のように書きました。request は RestSharp.RestRequest クラスのインスタンスです。
LoginInfo loginInfo = new LoginInfo("admin", "password"); var request = new RestRequest("api/v1/ticket", Method.POST); request.RequestFormat = DataFormat.Json; request.AddBody(loginInfo);
これは以下のように書くことも出来ます。
request.AddParameter( "application/json", "{\"username\": \"admin\", \"password\": \"password\"}", ParameterType.RequestBody );