らくがきちょう

なんとなく

C# から APIC-EM の REST API にアクセスする

Cisco Japan BlogSDN カテゴリー に「Python を使って APIC-EM の REST API にアクセスする」という記事が掲載されています。

(APIC-EM に限らず) PythonRuby から REST API にアクセスするサンプルはしばしば見かけるのですが、C# のサンプルはなぜか数が少ないきがします… (探し方が悪い?)。というわけで C# のサンプルを書いてみました。あくまでサンプルなのでエラー処理はしていません。

処理の大まかな流れ

実際に何がしかの REST API を利用する前に「ServiceTicket」と呼ばれる資格情報を取得する必要があります。よって、大まかな処理順序は以下のようになります。

  1. 適切な ID/Password を使って ServiceTicket を取得する
  2. 取得出来た 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 APIAPIC-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
    );