Qiita CLI
導入
Qiita公式がCLI上からQiitaに記事を投稿できるQiita CLIというツールを公開しています。
qiita-cliについて詳しくはこちらを参照してください
qiita-cliのインストール後の初期設定のために以下のコマンドを実行します
npx qiita login
実行後APIトークン
の入力を求められます
APIトークン
はこちらより新しく発行するか発行済みの値を入力して設定します
所感と課題
...APIトークン
の入力面倒くさくないですか?
APIトークン
の値とか失念しているでしょうし、新しくAPIトークン
をつくるのは面倒くさいですし...
このような初期設定の面倒臭さはqiita-cliのユーザー初心者にとってライブラリを使用する上での敷居の高さにつながっているように思います
他の事例
上記のような点を課題と感じたきっかけとして他のCLIツールでは API Key
の入力を求められることなく利用可能になるように作られているものが多く存在あります。
例えばGoogle App Scriptをローカルで開発するツールであるclaspを使用した場合のインストール後の初期設定のコマンドは以下の通りになります。
clasp login
上記のコマンドを実行するブラウザがたちあがり以下のような画面が表示されます
「次へ」を押すと以下の画面が表示されます
認可してもいい権限すべてをチェックして以下のように「続行」を押します
「続行」を押した後はOAuth認可が完了し、これでclaspの各種コマンドが実行できるようになります
clasp だけでなくfirebase-toolsなど、他のCLIツールにおいても初期設定時には同様の推移をたどることで初期設定をすることができます
qiita-cliにおいても同様なでも実現できたらいいなぁ...
claspの事例を参考にする
qiita-cliでもclaspと同様のインターフェースを実現させるためにclaspではどのように実現しているか参考にする。
とりあえずclaspにいて該当のソースコードが↓であるので見てみます。
詳しくはソースコードを見てください。
ソースコードより以下のことをやっていることが読み取れます
- CLIよりローカルサーバーを立ち上げる
- CLIよりGoogle OAuthの認可画面を開く
- 認可した時にローカルに戻ってくる (
http://localhost
) - 戻ってきたときにOAuth tokenの情報を取得して、その情報をマシンに記録する
以上のことを行っており、Google OAuth APIを使用しているがローカルの中だけで完結していることが読み取れます。
(またclaspにはGoogle OAuthに関する情報がすべてべた書きされている。事前にOAuth認可の戻り先のURLに http://localhost
を指定していると思われる)
なおclaspの実装内容を パク 参考にしてCLIの中だけでGoogle APIを使用することを実装して実現できたことを確認しました。
以下は確かめてみて実現できたプロジェクトです。(開発中につき解説などについては後日もう少し整理できてから行います)
またこのプロジェクトでは以下のようにOAuth認可の戻り先のURLに http://localhost
としてあらかじめ指定することでlocalhostに戻せることができることを確認しました。(ちなみにGoogleのOAuth APIの場合は http://localhost
と指定することでポート番号の区別なく(どのポート番号に)戻ることができます)
qiita-cliにおいてもclaspと同様のフローでのログインをするためには以下のことが実現可能である必要があります
- Qiita OAuth APIを利用できること
- Qiita OAuth APIの戻り先のURLにローカルホスト(
http://localhost
)を指定することができること
Qiita Oauth API
Qiita APIには認証認可(OAuth)の機能も存在します
導入方法についてはこちらのドキュメントを参考に導入していきます
とりあえずこのQiita Oauth APIを使ってCLIの中だけでQiita APIトークンを取得することを試みていきたいと思います。
Qiita OAuth APIの登録
ユーザーの管理画面 を選択し「アプリケーションを登録する」を選択してQiita OAuth APIを使用するための登録を行います
各種情報の入力します、この時「リダイレクトのURL」の部分には http://localhost:ポート番号
を指定して登録します。
※ Qiita OAuth APIではlocalhostのURLを指定することができましたが、ポート番号を指定する必要があります
無事に登録が完了すると Client Id
とClient Secret
の値が取得できるので実際に実装するときに使用するのでこの値を控えておきます。
CLIからQiita OAuth APIを介して実際にQiita API tokenを取得する
実際にNode.jsを使ってCLIを実行してローカルの中だけでQiita OAuth APIを介してQiita API Tokenを取得する処理を以下に記述します。
const qiitaOauthClientTokens = {
clientId: 'QiitaOAuthAPIClientId',
clientSecret: 'QiitaOAuthAPIClient Secret'
};
// OAuth認可を行う時に受け取るサーバのポート番号
const serverPortNumber = 59116;
async function startLocalServer(): Promise<Server> {
return new Promise<Server>((resolve) => {
const server = createServer();
enableDestroy(server);
server.listen(serverPortNumber, () => resolve(server));
});
}
async function recieveOauthCallbackCode(server: Server): Promise<string> {
return new Promise<string>((resolve, reject) => {
server.on(
'request',
(
request: ReadonlyDeep<IncomingMessage>,
response: ReadonlyDeep<ServerResponse>
) => {
const urlParts = new URL(request.url ?? '', 'http://localhost')
.searchParams;
const code = urlParts.get('code');
const error = urlParts.get('error');
if (code) {
resolve(code);
} else {
reject(error);
}
response.setHeader('Content-Type', 'text/plain;charset=utf-8');
// OAuth認可から戻ってきたときにブラウザ画面に表示させる内容
response.end('codeの取得が完了しました。ブラウザを閉じてください');
}
);
});
}
export async function oauthLogin(): Promise<string> {
const server = await startLocalServer();
// OAuth認可を行う時にローカル確認を行うためのstateを指定する必要があるのでてきとうな値を作る
const authorizeState = crypto.randomBytes(12).toString('hex');
const permissionScope = [
'read_qiita',
'write_qiita',
'read_qiita_team',
'write_qiita_team',
].join('+');
const qiitaAuthorizeUrl = `https://qiita.com/api/v2/oauth/authorize?client_id=${qiitaOauthClientTokens.clientId}&scope=${permissionScope}&state=${authorizeState}`;
await open(qiitaAuthorizeUrl);
const authCode = await recieveOauthCallbackCode(server).finally(() => {
server.destroy();
});
const accessTokenResponse = await getAccessToken(
qiitaOauthClientTokens.clientId,
qiitaOauthClientTokens.clientSecret,
authCode
);
return accessTokenResponse.data.token;
}
※上記処理を実行するために使用しているライブラリは以下の通りです。事前にyarn add
やnpm install --save
をして導入しておいてください
上記の処理を記述後以下のようにfunction
を呼び出します。
const token = await oauthLogin();
このようにCLIの中で呼び出すことで途中で以下のようにブラウザが立ち上がり「許可する」をおすと token
にQiita API tokenを取得できます
あとはこの token
をローカルファイルに記録するなりして活用することでQiita APIを実行することができます。
実は...
Qiita 公式がqiita-cliを公開するより前に私も非公式でqiita-cliというプロジェクトがありその開発(のお手伝い)をしていました。
こちらがForkして継続して開発していた私のプロジェクトとなります。
※なお Qiita OAuth API を利用するための Client Id
とClient Secret
の値は clasp 同様にソースコードにべた書きしていますが、ライブラリとして配布する場合はべた書きで公開状態でも問題ないと思われます。結局はローカル内で完結する話なので。
元々開発していた方が紹介している記事
Qiita記事管理CLI(qiita-cli)をTypeScriptでつくってみた
その中で今回のQiita OAuth APIを使ってCLIの中だけでログインすることができるのかどうかを検証していました。¥・
検証の結果実現できたのですが私の開発意欲の低下に伴い、放置となっ¥てしまいました
そして気が付いたらQiita公式がqiita-cliを作って公開したという状況となっていました。
役割を終えた形となりました。(無事、供養されると幸いです…)
公式のqiita-cliにてこのQiita OAuth APIを使ってのログイン機能の実装の導入のお手伝いをするかどうかについては依頼が来たらやろうかな...と考えています