mixiアプリのユーザーIDプラットフォーム共通化の移行方法

mixiが海外のSNSとプラットフォーム共通化をするらしく、その関係で、今まで数字のIDだったのが、文字列のIDに切り替わります。その関係で、mixiアプリ提供者は今月中(2011年10月)に新方式に移行が必要です。

http://developer.mixi.co.jp/news/news_apps/009668.html

なんか、あまり手法とかブログで見かけなかったので、やり方とか書いておきます。手抜きしたい方の参考にどうぞ。

まず、変わるのは、ID だけで、API は変わりません。今まで、ID を文字列で管理していた人は、データベースの ID さえ、差し替えてしまえば対応完了です。数値でやっていた人は、文字列にプログラムを書き換える必要があります。

一連の話、テストアプリで一通り練習してから、本番アプリで行ってくださいね。

ステップ1

http://developer.mixi.co.jp/appli/com/change/setting/trans_id/ にあるように、ID変換API の申請をします。アプリが稼働中の状態でやってしまっても、通常は大丈夫です。

ステップ2

まず、旧ID の一覧が必要です。in.csv は(1列のCSV、つまりカンマなし)で旧IDをずらずらと並べた形式にしました。

in.csv の作り方は、アプリ次第ですが、僕の場合は、PostgreSQL でこんな感じでした。

COPY (SELECT mixi_id FROM account_mixi) TO '/tmp/in.csv' CSV;

ステップ3

次は、旧ID → 新ID の変換です。RESTful API を使うと、変換表が手に入ります。こんな感じの Java のアプリでやりました。http://code.google.com/p/opensocial-java-client/ が必要です。

java -classpath .;opensocial-1.0.jar;commons-codec-1.3.jar;json_simple-1.1.jar;oauth-20090825.jar MixiOldIdConverter in.csv out.csv failed.csv

で実行します。一度実行したら、out.csv や failed.csv に保管するので、2回目は差分だけ実行できます。1回目は、アプリが動いた状況で実行し、その後必要なら、数回、アプリが実行している状態で行い、最後にアプリを停止して変換すると、アプリの停止時間を小さく出来ます。

import org.opensocial.Client;
import org.opensocial.Request;
import org.opensocial.RequestException;
import org.opensocial.Response;
import org.opensocial.auth.OAuth2LeggedScheme;
import org.opensocial.models.Model;
import org.opensocial.services.PeopleService;

import java.io.*;
import java.util.Date;
import java.util.HashSet;

public class MixiOldIdConverter {
    // 本番
    private static final String consumerKey = "fuga";
    private static final String consumerSecret = "barbar";
    // テスト
//    private static final String consumerKey = "fugaTest";
//    private static final String consumerSecret = "barTest";

    public static void main(String[] args) throws IOException {
        File inFile = new File(args[0]);
        File outFile = new File(args[1]);
        File failedFile = new File(args[2]);

        HashSet<String> converted = new HashSet<String>();
        readOutFile(outFile, converted);
        readOutFile(failedFile, converted);

        BufferedReader reader = new BufferedReader(new FileReader(inFile));
        PrintWriter writer = new PrintWriter(new FileWriter(outFile, true));
        PrintWriter failedWriter = new PrintWriter(new FileWriter(failedFile, true));

        int lineNo = 0;
        String line;
        while((line = reader.readLine()) != null) {
            if (line.length() == 0) continue;
            if (converted.contains(line)) continue;
            lineNo++;

            try {
                String platformUserId = convert(line);
                writer.println(line + "," + platformUserId);
            } catch (Exception e) {
                //e.printStackTrace(); // ここコメントアウトしてもあまり問題ない
                failedWriter.println(line);
            }

            if ((lineNo % 10) == 0) System.out.println(lineNo + " " + new Date());
        }

        failedWriter.close();
        writer.close();
        reader.close();
    }

    private static void readOutFile(File outFile, HashSet<String> converted) throws IOException {
        if (outFile.exists()) {
            BufferedReader reader = new BufferedReader(new FileReader(outFile));
            String line;
            while((line = reader.readLine()) != null) {
                if (line.length() == 0) continue;
                converted.add(line.split(",")[0]);
            }
            reader.close();
        }
    }

    public static String convert(String oldId) throws IOException, RequestException {
        OAuth2LeggedScheme authScheme = new OAuth2LeggedScheme(consumerKey, consumerSecret, oldId);
        Client client = new Client(new MixiProvider(), authScheme);

        Request viewer = PeopleService.getViewer();
        viewer.addParameter("fields", "platformUserId");
        Response response = client.send(viewer);
        Model person = response.getEntry();

        return (String) person.getField("platformUserId");
    }
}
import org.opensocial.providers.Provider;

public class MixiProvider extends Provider {
    public MixiProvider(){
        super();

        setName("mixi");
        setVersion("0.8");
        setSignBodyHash(false);
        setRestEndpoint("http://api.mixi-platform.com/os/0.8/");
    }
}

ステップ4

  1. Webアプリを停止する。
  2. データベースのバックアップをとる。
  3. in.csv の最終形を作る。
  4. 変換して、out.csv の最終形を作る。
  5. この後記載する SQL みたいな感じで、新 ID に置き換える。
  6. 念のため、別なファイル名で、再度、データベースのバックアップをとる。
  7. 「IDのプラットフォーム共通化対応完了」をクリック。これ以降、新 ID で mixi の方からは応答が来るようになります。
  8. Webアプリを再開する。
CREATE TABLE old_new_mixi_id_map (
  old_mixi_id VARCHAR(255) PRIMARY KEY,
  new_mixi_id VARCHAR(255) NOT NULL
);

COPY old_new_mixi_id_map FROM '/tmp/out.csv' CSV;

UPDATE account_mixi SET mixi_id = 
  (SELECT new_mixi_id FROM old_new_mixi_id_map 
    WHERE old_new_mixi_id_map.old_mixi_id = account_mixi.mixi_id)
  WHERE mixi_id in (SELECT old_mixi_id FROM old_new_mixi_id_map);

場合によっては、他にも関連するテーブルの情報を削除する場合がアプリによってはあると思います。(僕の場合は、他に2カ所、データを削除しました)