JavaScript を利用して Movable Type へデータを登録する

[Google Books API + Movable Type で書籍管理システムを作る](http://qiita.com/TakeshiNickOsanai/items/a11b2d6c9cdc4a6c9079)  その5です。今回は、Java Script を利用して、Movable Type へデータを登録する (=記事を投稿する) 方法について、簡単に解説します。

以下のような流れとなります。

- Movable Type へサインインする(認証を行う)
- フォームから入力された値を受け取り、MTへ登録するためのデータを生成する
- Data API 経由でデータを登録 (記事を投稿) する

## 実際のコード

上記の流れを、1枚のコードにまとめてみました。

下記のコードを Movable Type のテンプレート (インデックステンプレートなど)に貼り付けて、再構築を行うと、実際に記事投稿できるフォームが出力されます。

```
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>記事登録サンプルフォーム</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <script src="<$MTStaticWebPath$>data-api/v3/js/mt-data-api.js"></script>

  <script>

  $(function() {

    "use strict";

// Movable Type Data API のインスタンス生成

    const api = new MT.DataAPI({
      baseUrl: "<$MTCGIPath$><$MTDataAPISCript$>",
      clientId: "JSPost-sample"
    });

// MTのブログIDを変数 siteId に格納

    const siteId = <$MTBlogID$> ;

// メッセージ表示のために使う変数 [html] を定義
       
    let html = '';

// MTにサインインしているかどうか、トークンを確認する。
// トークンがない場合、サインインを促す。存在した場合、hiddenで隠されている登録用フォームを表示する

    if (!api.getTokenData()) {

      html += "<p>記事を登録するためにはサインインしてください。</p>";
      html += "<p><input type=\"button\" id=\"signin\" class=\"btn btn-primary btn-lg\" value=\"サインイン\"></p>";
      $("#message").html(html);

    } else {

      $("#content").show();
    }

// サインインをクリックしたら、SDKの関数 [getAuthorizationUrl] を実行して、サインインを行う

    $("#signin").on("click", function() {
      location.href = api.getAuthorizationUrl(location.href);
    });

// フォームを表示して、MTへ登録するためのデータを受け取る
// 登録ボタンをクリックしたら、MTへ登録するための変数を生成する。
// 変数が準備できたら、JavaScript SDK の関数 [createEntry] を利用して、MTの記事として登録する。

    $("#submit").on("click", function() {

      const entry = {};
        entry.title = $("#title").val();
        entry.body = $("#body").val();
        entry.more = $("#more").val();

      api.createEntry(siteId, entry, function(response) {

        if (response.error) {

  // 記事登録時にエラーが発生した場合、ページトップに戻り、エラーメッセージを表示
                             
          $('html,body').animate({ scrollTop: 0 }, '1');
          $("#message").html('<p class="bg-warning">エラーが発生しました。</p>');
          $('#message > p').fadeOut(3000);

        } else {

  // 記事データ登録が成功した場合、表示データを消去

          $("#title").val("");
          $("#body").val("");
          $("#more").val("");


  // ページトップに戻り、登録完了のメッセージを表示
                             
          $('html,body').animate({ scrollTop: 0 }, '1');
          $("#message").html('<p class="bg-warning">記事を登録しました。</p>');
          $('#message > p').fadeOut(3000);

        }

      });

    });

  });

  </script>

</head>
<body>

<div class="container" id="container">

  <h1>JavaScriptでMTに投稿するサンプルコード</h1>
  <div id="message"></div>

  <div id="content" style="display: none;">
    <div>
      <p class="h3">タイトル:</p>
      <input type="text" class="form-control" id="title" placeholder="タイトル">
    </div>

    <div>
      <p class="h3">本文:</p>
      <textarea class="form-control" rows="5" id="body"></textarea>
    </div>


    <div>
      <p class="h3">続き:</p>
      <textarea class="form-control" rows="5" id="more"></textarea>
    </div>

    <button class="btn btn-default" id="submit">登録する</button>

  </div>
</div>

</html>
```

簡単に説明します。

まず最初に、ヘッダー内でjQuery、BootStrapなどのライブラリとともに、Movable Type のJavaScript SDK を読み込んでいます。JavaScript SDK については、[Movale Type Data API のエンドポイントとJavaScript SDK の使い方](http://qiita.com/TakeshiNickOsanai/items/05120e295ee1aab59017) をご参照ください。

## 認証を行うコード

次に、JavaScript で認証を行うためのコードを記述しています。認証については、 [Movable Type の Data API でユーザー認証を行う](http://qiita.com/TakeshiNickOsanai/items/5508b2df13be72bf4503) に詳しく書いています。

今回のコードでは

- サインインボタンをクリックすると、Movable Type のサインイン画面が呼び出される
- ユーザー名、パスワードを正しく入力すると、認証が行われ、アクセストークンがCookie に保存される

という流れを実装しています。

```
    if (!api.getTokenData()) {

      html += "<p>記事を登録するためにはサインインしてください。</p>";
      html += "<p><input type=\"button\" id=\"signin\" class=\"btn btn-primary btn-lg\" value=\"サインイン\"></p>";
      $("#message").html(html);

    } else {

      $("#content").show();
    }

// サインインをクリックしたら、SDKの関数 [getAuthorizationUrl] を実行して、サインインを行う

    $("#signin").on("click", function() {
      location.href = api.getAuthorizationUrl(location.href);
    });
```

## Movable Type へ記事を登録するための関数 [createEntry]

フォームから入力が行われ、｢登録｣ボタンが押されたら、フォームから値を受け取ります。Movable Type へ記事データを登録するためのエンドポイントを利用して、データを登録します。

記事の登録のためのエンドポイントは こちらになります。

https://www.movabletype.jp/developers/data-api/v3-reference.html#entries-entries-post

このエンドポイントに対して、タイトルや本文データ、およびアクセストークンを正しくPOSTすると、記事が登録されます。

[JavaScript SDK](http://qiita.com/TakeshiNickOsanai/items/05120e295ee1aab59017) では、このエンドポイントを利用して記事データを登録するための [createEntry](https://github.com/movabletype/mt-data-api-sdk-js/wiki/DataAPI-SDK-japanese-MT.DataAPI-Endpoint-method-createEntry)　という関数があります。今回は、この関数を利用しています。

Movable Type に限らず、REST API を利用してデータのやり取りをする場合、APIが定義する型にあわせて、データを整形する必要があります。

Movable Type の記事データの型は、以下のようになります。
(Movable Type の [APIリファレンス](https://www.movabletype.jp/developers/data-api/v3-reference.html#entries)より引用 )

```
{
      "excerpt" : "We are excited to announce that Six Apar...",
      "status" : "Publish",
      "date" : "2014-11-14T13:08:42¥u002b09:00",
      "updatable" : false,
      "author" : {
        "userpicUrl" : null,
        "displayName" : "Yuji Takayama"
      },
      "allowComments" : true,
      "comments" : [],
      "permalink" : "http://localhost/blog/20141114-1/2014/11/six-apart-acquires-topics-server-to-simplify-site-upgrades.html",
      "body" : "¥u003cp¥u003e¥u003cspan¥u003eWe are excited to announce that Six Apart has acquired Topics, a dynamic online publishing product. This offering will provide Six Apart customers with an easy and cost-effective way to adapt existing content to evolving digital platforms.¥u003c/span¥u003e¥u003c/p¥u003e¥n¥u003cp¥u003e¥u003cspan¥u003eThis new product will save Six Apart customers a significant amount of time and money by allowing users to upgrade their websites and applications without migrating from their current content management systems. Clients who need to scale large amounts of data or even revamp a website on an entirely new platform can now achieve these changes with minimal effort.¥u003c/span¥u003e¥u003c/p¥u003e¥n¥u003cp¥u003e¥u003cspan¥u003eSix Apart customers will benefit not only from saved time and money, but also from ease of use. Topics does not have a user interface, so there is no new software to learn. Instead, it exists as a middle layer between the data library and the published page - automatically gathering, organizing and redistributing data.¥u003c/span¥u003e¥u003c/p¥u003e",
      "keywords" : "",
      "allowTrackbacks" : false,
      "id" : 5,
      "trackbacks" : [],
      "modifiedDate" : "2014-11-14T13:17:52¥u002b09:00",
      "trackbackCount" : "0",
      "categories" : [],
      "blog" : {
        "id" : "1"
      },
      "commentCount" : "0",
      "tags" : [],
      "basename" : "six_apart_acquires_topics_server_to_simplify_site_upgrades",
      "assets" : [],
      "pingsSentUrl" : [],
      "title" : "Six Apart Acquires Topics Server to Simplify Site Upgrades",
      "class" : "entry",
      "createdDate" : "2014-11-14T13:17:52¥u002b09:00",
      "unpublishedDate" : "2014-11-14T13:17:52¥u002b09:00",
      "more" : "",
      "customFields" : [
        {
          "basename" : "place",
          "value" : "New York City"
        },
        {
          "basename" : "agenda",
          "value" : "Movable Type¥nTopics"
        }
      ]
    }
```

今回のサンプルでは、シンプルに

- タイトル
- 本文
- 続き

の3つのデータを登録しています。この3つのデータを、 APIリファレンスの型を参考にしながら変数[entry] に格納して、登録を実行しています。

タイトルは[title] 。
本文は[body]。
続きは[more]。

として、それぞれフォームから入力されたデータをバインドして、Movable Type に登録します。


```
// 登録ボタンをクリックしたら、MTへ登録するための変数を生成する。
// 変数が準備できたら、JavaScript SDK の関数 [createEntry] を利用して、MTの記事として登録する。

    $("#submit").on("click", function() {

      const entry = {};
        entry.title = $("#title").val();
        entry.body = $("#body").val();
        entry.more = $("#more").val();

      api.createEntry(siteId, entry, function(response) {

        if (response.error) {

  // 記事登録時にエラーが発生した場合、ページトップに戻り、エラーメッセージを表示
                             
          $('html,body').animate({ scrollTop: 0 }, '1');
          $("#message").html('<p class="bg-warning">エラーが発生しました。</p>');
          $('#message > p').fadeOut(3000);

        } else {

  // 記事データ登録が成功した場合、表示データを消去

          $("#title").val("");
          $("#body").val("");
          $("#more").val("");


  // ページトップに戻り、登録完了のメッセージを表示
                             
          $('html,body').animate({ scrollTop: 0 }, '1');
          $("#message").html('<p class="bg-warning">記事を登録しました。</p>');
          $('#message > p').fadeOut(3000);

        }

      });

    });
```


記事が正常に登録されたら、登録完了のメッセージを、jQueryを利用して表示します。


[書籍管理システム](http://qiita.com/TakeshiNickOsanai/items/a11b2d6c9cdc4a6c9079)　の [登録フォーム](https://github.com/Nick-smallworld/mt-theme-BookShelf-sample/blob/master/themes/Bookshelf-sample/templates/main_index.mtml)　では、上記のサンプルコードを応用して、カスタムフィールド用のデータなども変数に格納して、登録を行っています。

カスタムフィールドのデータは、多次元連想配列として生成、登録を行っています。