SpotifyWebAPIの認可フローをまとめてみた

以前、
SpotifyAPIでクイックプレイリスト作成ツールを作ってみた

で簡単にSpotifyWebAPIの使い方を紹介しましたが、今回リニューアルに向けてSpotifyWebAPIの認可フローをまとめてみました!!!
(ちょい長めなので、飽きないように絵文字多めでうざいかもしれませんw)

公式ドキュメント:https://developer.spotify.com/documentation/general/guides/authorization-guide/
のほとんど和訳みたいな感じですが…😅

Spotify APIを使うフローは3つあります。

  • Authorization Code
    リフレッシュ可能なユーザ認可。エンドユーザ情報にアクセスするAPIエンドポイント(プレイリスト作成も可能)もアクセスできる。
  • Implicit Grant Flow
    一時的なユーザ認可。JavaScriptを使いエンドユーザブラウザで実行される。サーバ側のコードを使用しないアプリ向け、refresh_tokenの提供なし。
  • Client Credentials Flow
    リフレッシュ可能なアプリ認可。サーバ間認証で、エンドユーザ情報にアクセスにしないAPIエンドポイントのみにアクセスできる。

今回はPHPを使う想定で、
Authorization Codeについての詳細を紹介します!!!

Spotify Web APIでつかうURLは2つあります。

  • https://accounts.spotify.com
    Spotifyアカウント(ユーザ認可)へのAPI用👦
  • https://api.spotify.com/
    それ以外(アーティスト・プレイリスト・トラックなど)のSpotifyサービスへのAPI用🎧

ざっくりとした流れは、以下stepになります。

1.認可リクエスト🙇‍♂️

GET https://accounts.spotify.com/authorize

<クエリパラメータ>

クエリパラメータ
client_id SpotifyのDeveloperにあるやつ(必須)
response_type "code"をセットする。(必須)
redirect_uri SpotifyのDeveloperより設定したRedirect URIsと同じものにする(必須)
status ランダム文字列をセットをすると、リクエストとレスポンスが妥当かの確認できて、クロスサイトリクエストフォージェリなどの攻撃に対する保護ができる。[RFC-6749](推奨)
scope デフォルトはSpotifyデスクトップやweb、モバイルプレーヤで通常表示される情報のみアクセスを許可する設定になる。
詳細は、Authorization Scopes
show_dialog [default:false] falseの場合、一度承認すると自動でredirect_uriにリダイレクトする。trueの場合、既に承認していてもredirect_uriにリダイレクトされず、再度認証を

具体例

GET https://accounts.spotify.com/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=user-read-private%20user-read-email&state=34fFs29kd09

をすると、

  1. クエリパラメータ指定のscopeについて、エンドユーザに認可していいか尋ねる
    • エンドユーザがログインしていない場合:ログインを求める
    • エンドユーザがログイン済の場合:スコープについてのデータアクセスへの許可/拒否かを聞く
  2. エンドユーザはredirect_uriにリダイレクトされる
    • エンドユーザが認可を許可した場合🙆‍♂️:
      codeとstate(リクエストで指定してた時のみ)がクエリパラメータとして返ってくる。
    • code:access_tokenと交換できる認証コード
      例)https://example.com/callback?code=NApCCg..BkWtQ&state=profile%2Factivity

    • エンドユーザが認可を拒否した場合🙅‍♂️:
      errorとstate(リクエストで指定してた時のみ)
    • error:認可失敗の理由
      例)https://example.com/callback?error=access_denied&state=STATE

2.refresh_tokenとaccess_tokenをリクエストする🔑

認可コード(code=xxxx)を受け取った後、認可コードとaccess_tokenを交換するためにリクエストする

POST https://accounts.spotify.com/api/token

<リクエストボディパラメータ>
OAuth 2.0で定義されたapplication/x-www-form-urlencodedでエンコードされたパラメータを含ませる必要がある。

リクエストボディパラメータ
grant_type "authorization_code"をセットする(必須)
code 1で取得したcodeをセットする(必須)
redirect_uri 妥当性の検証に使用されるだけで、リダイレクトはしない。1でリクエストしたredirect_uriと一致する必要がある(必須)
client_idとclient_secret もしくはヘッダーパラメータにAuthorization: Basic <?php base64_encode(client_id:client_secret)>を含める(必須)

<レスポンスデータ>

レスポンスデータ
access_token 今後のSpotifyWebAPIサービスを利用するためのaccess_token
token_type "Bearer"
scope access_tokenに付与されたscope、スペース区切りのリスト文字列
expires_in access_tokenの有効な期間(秒単位)
refresh_token access_tokenが期限切れになった時、新しいaccess_tokenを得るために必要となるっぽい

3. access_tokenを使って、SpotifyWebAPIへアクセスする🎧

2で受け取ったaccess_tokenを使用(ヘッダーにセット)し、リファレンスに沿ってリクエストをするとで、ユーザに代わってSpotifyWebAPIにリクエスト/レスポンス(JSON)を受け取ることができる。

例)
curl -H "Authorization: Bearer {access_token}" https://api.spotify.com/v1/me

Web API Reference
https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-check-current-user-follows

4.access_tokenをリフレッシュする方法✨

access_tokenは、しばらくすると意図的に期限切れになります。
その後、認可コードとの交換で最初に取得したrefresh_tokenを使用して新しいaccess_tokenをもらう。

POST https://accounts.spotify.com/api/token

<リクエストボディパラメータ>
OAuth 2.0で定義されたapplication/x-www-form-urlencodedでエンコードされた、リクエストボディパラメータを含ませる。

  • grant_type:refresh_tokenをセットする(必須)
  • refresh_token:認可コード交換の時に返されたrefresh_tokenをセットする

<へッダーパラメータ>

  • Authorization:Authorization: Basic <?php base64_encode(client_id:client_secret)>(必須)

まとめ

改めて日本語でまとめてみると、ユーザ情報にもアクセスするのでセキュリティ面で考えることもできました。

  • statusをセットした方が、安全そう
  • client_secretなどの他人にバレてはやばそうな情報を使ったリクエストを送る時はOAuth 2.0で定義されたapplication/x-www-form-urlencodedでエンコードしてる
  •  
     
     

PHPerKaigi2020前夜祭だけ行ってきたよー!

お久しぶりです!PHPerKaigi2020前夜祭だけ行ってきましたー!
(1日目は月曜平日なので、チキってしまいました。)
名古屋-東京って新幹線ですぐなのに、片道一万もするのどうにかならないですかねえ😌

間違えてペチコンの流れで京急蒲田にむかっておりました。品川で気づかされました。

さて、入場してもらえたもの(勝手にピックアップ)

  • トートバッグ(ジーパン生地かわいい)
  • 名札
  • トレンディングカード(プロフィール登録ミスっててアイコンがない…)
  • GameWithさんのモバイルバッテリー(これはありがたいです🙇‍♂️)
  • デジタルサーカスさんの熱伝導式のアイススプーン(ほんとにカチカチのアイス食べやすかったです)
  • GMOさんのチョコ

参加したセッション

Deep module in PHP

前提:いいコード=複雑じゃないコード
=内容を理解するのが簡単で、変更するのが大変ではない とする

どうやって複雑で名はないコードを書くか?
→ Deep module

Deep module とは?
- モジュール設計の考え方
- 様々な角度から複雑さを減らす方法 例)技術的負債、抽象化、エラー

モジュールとは?
→インターフェイスと実装をもつあらゆるレベルにおけるコードの塊

インターフェイスとは?
→他のモジュールがそのモジュールを呼び出すために知る必要があるもの

理想のモジュール
→多くの機能を提供しながら、インターフェイスはシンプルなもの

Deep module ⇔ shallow  module

- moduleが深くなることを目指す
  - 抽象化することを意識する
    重要ではない実装の詳細を隠すことで、インターフェイスをシンプルにできるかつ多機能の両立ができる
  - 可能な限り、一般的なケースに最適化された設計を行う

deep moduleの具体例🙆‍♂️
- CakePHPのsaveメソッド …詳細を知らなくてもデータを保存できる
  - エンティティ渡すだけでよい →シンプルなインターファイス
  - インサートかアップデートかどちらかをよしなにしてくれる →多機能(cakePHPでは、save時にcreated/modifiedをするか自動で決めるのは一般的な機能)
  ↑ある種の決めつけで、インターフェイスをシンプルにしている
  - データベースの種類を意識する必要がない →抽象化

shallow moduleの具体例より🙅‍♂️
小さなモジュールだけど、インターフェイス(メソッド名)に実装詳細がダダ漏れしている。
エンティティ操作をするサブクラスだが、直接エンティティから操作したほうが早い。
→ インターフェイスのコストが、機能の利益を上回っている

しかし、小さい(モジュール)はいいことなのでは?
例) Sandy metzルール(クラス内コードは100行以内、メソッドは5行以下) ←Ruby

↓

小さいことはNot Shallow!
- モジュールが小さいと持っている情報量が少なく、多機能ではないから
→何でもかんでもメソッド化するのは良くない

- 1つのメソッド内に大量のコードが書かれると読みづらい
→ 実装が膨れたら、適宜メソッドに分割する


まとめ

Deep moduleとは、、、
インターフェイスがシンプルで、多機能なモジュール
このモジュールはDeepか?という問いにを立てながらコードを書くと良いコードになるかも

マルチパラダイムモデリング

- オブジェクトの歴史

  - 構造化プログラミング     
  - モジュラープログラミング
   ↓
  - データ抽象
    ↓ データ抽象を実現する手段の一つとして提唱されたのが、抽象データ型
  - 抽象データ型
   ↓ さらに、抽象データ型の具体的実装としてクラスに多くの機能を導入
  - クラス 🌟モジュール化の手法のひとつ!
  
  - ここまでのまとめ: クラスベースのオブジェクト指向におけるソフトウェア構築は、抽象データ型の構造化された集合としてシステムを構築すること

- マルチパラダイム・モデリング
  - 関数を他のデータ型同様に扱うことによって、モジュール間の依存関係を適切にできる可能性がある。(関数がファーストクラスオブジェクトである)🤔
  - 抽象データ型は、データ構造を隠蔽するため、データモデルの理解は必要不可欠🤔

- 計算モデル
  - チューリングマシーンとは?...チューリングさんが提唱した

>「計算可能性」に関する議論のために提示した抽象機械である。

調べたけど[宇宙一わかりやすい](https://www.yukisako.xyz/entry/turing-machine)でもわからなかった、、

  - (帰納的関数、よくわかってない...)

- 計算モデルとしてのデータモデル

  - データモデルを用いることで計算を行いやすくなるという意味で計算モデルとみなすことができる
  
    例)リレーショナルモデル → リレーショナル演算
  
  - ただし、チューリング完全であるとは限らない🤔
  
  - リレーショナルモデルとERモデル
  
    - リレーショナルモデル ...述語理論、なんらかの命題を満たす事実の集合を捉えるデータモデル。関係演算によるデータ操作が可能になる。
    
    - ERモデルはリレーショナルモデルではない?
      - リレーショナルモデル 計算携帯持つ
      - ERモデル それ自体は計算携帯をもたない。複数のデータモデルの包括的なビュー。

私のレベルではちょっと難しいお話でした...勉強します...

Inside SWOOLE:非同期処理はどのようにして動くのか

- swooleとは?
  - PHPで非同期処理を実現できる機能拡張
  - 2012年~
  - Transfonさんによって
  - 中国の開発者が猛烈

- 非同期処理
  - 並行/並列
  - コルーチン?

- C++でできている

- swooleまだまだ開発環境レベルでしか使用できてない、本番で使ってる例は少なそう。(会場内で使ってるのは、uzullaさんと郡山さんくらいだった)

BEAR.Sundayのマニュアルにもswooleが追加されていたので気になってました。

感想

  • トレンディングカードもっと交換したかった😭(切実)
  • フェスみたいに一日券が欲しい。
    例)前夜祭のみとか、1日目のみなど
  • 地方枠でちょい安なチケットが欲しい。(現在地証明が難しそうだけど)
  • もっと勉強しよ…

とはいっても、とても楽しかったです!実行委員のみなさんありがとうございました🙇‍♂️
来年も楽しみにしています!!!

Symfony4をHerokuにデプロイしてみる

 

Symfony Advent Calendar 2019の14日目です。(間に合わすつもりでしたが、過ぎてしまいました…)

 

ほとんど、Herokuのドキュメント通りですが、 Apache設定に関して忘れがちなので同じ経験をしている方の助けになればと思います!

Githubにコミットしてるので、参考にどうぞ!
kin29/symfony4-heroku

 

使うもの

– Symfony4.4
– Heroku (Apacheを想定)

 

確認事項

Symfony4.4はPHP7.1.3以上が必要です。

$ php -v  //ローカルのPHPのバージョンを確認
PHP 7.1.30 (cli) (built: Jul 4 2019 21:55:42) ( NTS )

 

※ 今のHerokuのデフォルトPHPバージョンは7.3.12でした!

-----> PHP app detected
-----> Bootstrapping...
-----> Installing platform packages...
       - php (7.3.12)
       - apache (2.4.41)
       - nginx (1.16.1)

 

手順

1.composer経由でプロジェクトの作成

$ composer create-project symfony/website-skeleton symfony4-heroku/

ビルドインサーバーを立ててローカルで確認してみる。

$ cd symfony4-heroku/
$ php -S 127.0.0.1:8888 -t public/

welcomeページ見れましたー!

 

2.Herokuにデプロイしてみる

Githubにpushして、masterをdeployしてみます。

なんかエラーになって、deployできない。

...
     Script cache:clear returned with error code 255
       !!  Symfony\Component\ErrorHandler\Error\ClassNotFoundError {#29
       !!    #message: """
       !!      Attempted to load class "WebProfilerBundle" from namespace "Symfony\Bundle\WebProfilerBundle".\n
       !!      Did you forget a "use" statement for another namespace?
       !!      """
       !!    #code: 0
       !!    #file: "./src/Kernel.php"
       !!    #line: 23
       !!    trace: {
       !!      ./src/Kernel.php:23 {
       !!        App\Kernel->registerBundles(): iterable
       !!        › if ($envs[$this->environment] ?? $envs['all'] ?? false) {
       !!        ›     yield new $class();
       !!        › }
       !!      }
       !!      ./vendor/symfony/http-kernel/Kernel.php:449 { …}
       !!      ./vendor/symfony/http-kernel/Kernel.php:133 { …}
       !!      ./vendor/symfony/framework-bundle/Console/Application.php:169 { …}
       !!      ./vendor/symfony/framework-bundle/Console/Application.php:75 { …}
       !!      ./vendor/symfony/console/Application.php:148 { …}
       !!      ./bin/console:42 { …}
       !!    }
       !!  }
       !!  2019-12-14T12:26:54+00:00 [critical] Uncaught Error: Class 'Symfony\Bundle\WebProfilerBundle\WebProfilerBundle' not found
       !!  
       Script @auto-scripts was called via post-install-cmd
 !     WARNING: There was a class not found error in your code
 !     ERROR: Dependency installation failed!
 !     
 !     The 'composer install' process failed with an error. The cause
 !     may be the download or installation of packages, or a pre- or
 !     post-install hook (e.g. a 'post-install-cmd' item in 'scripts')
 !     in your 'composer.json'.
 !     
 !     Typical error cases are out-of-date or missing parts of code,
 !     timeouts when making external connections, or memory limits.
 !     
 !     Check the above error output closely to determine the cause of
 !     the problem, ensure the code you're pushing is functioning
 !     properly, and that all local changes are committed correctly.
 !     
 !     For more information on builds for PHP on Heroku, refer to
 !     https://devcenter.heroku.com/articles/php-support
 !     
 !     REMINDER: the following warnings were emitted during the build;
 !     check the details above, as they may be related to this error:
 !     - There was a class not found error in your code
 !     Push rejected, failed to compile PHP app.
 !     Push failed

 

herokuのdeployではcomposer require-devのほうは、インストールしてくれないそうなので、symfony/profiler-packがないよーって言っています。

横着ですが、
require-devのパッケージを、requireの方にも入れます。

       !!  Symfony\Component\ErrorHandler\Error\ClassNotFoundError {#29
       !!    #message: """
       !!      Attempted to load class "WebProfilerBundle" from namespace "Symfony\Bundle\WebProfilerBundle".\n
       !!      Did you forget a "use" statement for another namespace?
       !!      """

 

こっちも、composer.jsonのscript部分の消しちゃって逃げます💦

-    "scripts": {
-        "auto-scripts": {
-            "cache:clear": "symfony-cmd",
-            "assets:install %PUBLIC_DIR%": "symfony-cmd"
-        },
-        "post-install-cmd": [
-            "@auto-scripts"
-        ],
-        "post-update-cmd": [
-            "@auto-scripts"
-        ]
-    },

で、どうにかHerokuにデプロイできるようになりました😎

 

3.env=prodにする

heroku config:set APP_ENV=prod --app [herokuのapp名]

4.Apacheの設定 ←ここ大事💡

以下コマンドでProcfileを作成します。

$ echo 'web: heroku-php-apache2 public/' > Procfile

さらに、composer require apache-packを実行し、質問にはyesで答えます。
そうすると、.htaccessが追加されます。

git pushしてherokuにdelpoyされたら、ブラウザで確認してみます。
env=prodでは、welcomeページはないので404になります。

 

5.コントローラー作成

下記コマンドで、コントローラを作成することができます。

$ php bin/console make:controller HogeController

 created: src/Controller/HogeController.php
 created: templates/hoge/index.html.twig

           
  Success! 
           

 Next: Open your new controller class and add some pages!

deploy後にheroku bashで、routerを一応確認してみます。良さそう😏

~ $  bin/console debug:router
 ------ -------- -------- ------ -------
  Name   Method   Scheme   Host   Path
 ------ -------- -------- ------ -------
  hoge   ANY      ANY      ANY    /hoge
 ------ -------- -------- ------ -------

6.ブラウザチェック

作成した/hogeにアクセスしてみると、、、見れたー!!!!!🎉

つまづきポイント

deployできたはずなのに、herokuでsymfonyコマンド使ってみると、 最初のエラーが再び….
Attempted to load class “WebProfilerBundle” from namespace “Symfony\Bundle\WebProfilerBundle”.\n
Did you forget a “use” statement for another namespace?
heroku run bashして、サーバに入ってrm -rf vendor/からのcomposer installでどうにかsymfonyコマンドは動作するようになりました。

 

参考

https://devcenter.heroku.com/articles/deploying-symfony4
https://github.com/heroku/heroku-buildpack-php/issues/278#

 



URIとURLの違い

 

先日、PHPカンファレンスで購入した「Webを支える技術」を読んでいて、
URIとURLの違いを今更あんまり理解できてないとわかったので、まとめてみます。

URLとURIの意味は?

  • URL …Uniform Resource Locator(統一リソース位置指定子)
  • URI …Uniform Resource Identifier(統一リソース識別子)

もう一つ似た言葉があります!

  • URN …Uniform Resource Name(統一リソース名)

 

URLとは?

リソースの場所を示すもの。

 

URNとは?

ドメイン名に依存しない、独立したリソース名。URLがドメイン更新切れだったり、サーバの障害でアクセスできないときに、恒久的にIDを振るための仕様。

しかし、URLは永続的にアクセスできるべきという考えから、URNは使うまではないことが多くなり、普及していない。

 

URIとは?

リソースを識別するもの。

URIが位置的なものを示したい時はURL、URIが名前を示したいときはURN

→URIは、URLとURNの両方の意味を含むもの

まとめ

  • URL⇄URIと読み替えても、だいたいはok。
  • 詳しく言うと、URLはURIであり、URNもURIである。
  • URIの方が広い意味で使えるので便利だし、技術者っぽい

 

参考:https://qiita.com/Zuishin/items/3bd56117ab08ec2ec818

PHPカンファレンス2019に行ってきましたレポート

さっそくですが、先日PHPカンファレンス2019に参加してきたので、超簡単にダイジェストをお送りします。

今年のPHPカンファレンスは、どこの地方も参加できてなかったので、久々のカンファレンスで高まりました!!!

今年も、会場は大田区産業プラザ PiOでした。毎年同じ場所だと東京の土地勘がないわたしにはとてもありがたいです!

毎回思いますが、人多いですね!

セッション「PHPの今とこれから2019

PHP8.0

  • 2021.9くらいにでる予定らしい
  • JIT(Just-in-time)
  • multiple(union) typeの型指定をint|stringって書けるようになる

今までは、PHPDocのアノテーションでいい感じにしてた。

class Hoge
{
  /**
   * @param int|string
   */
  public function foo($value): void
  {
    var_dump($value);
  }
}

$hoge = new Hoge;
$hoge->foo(1);           //int(1)
$hoge->foo('one');  //string(3)

PHP8から、こうやってかけるようになるらしい

class Hoge
{
  public function foo(int|string $value): void
  {
    var_dump($value);
  }
}

PHP7.4

 

参考:https://www.amitmerchant.com/union-types-php/
参考:https://qiita.com/rana_kualu/items/ba312d2789bd228f887a
参考:https://kinsta.com/jp/blog/php-7-4/

セッション「コミュニティアップデート powered by GMOインターネット

PHPの地方コミュニティのいろいろを聞けました。

  • 勉強会やイベントでの自己紹介って結構大事らしい
  • 山陰ぺちぱーずという、地元に割と近いコミュニティがあるのを知った

 

セッション「思想と理想の果てに — クリーンアーキテクチャのWEBフレームワークを作ろう」

https://nrslib.com/phpcon-2019-proposal/

  • ヘキサゴナルアーキテクチャ(初耳)
  • スキャフォールディング機能(初耳)

 

セッション「PHPUnit: Past, Present and Future 」

PHPUnitの生みの親、セバスチャンさんの登壇でした!
全部英語です。こういう時に毎回英語頑張っておけばよかったと思います😂

心から言いたいことは「PHPUnitを作ってくれて、ありがとうございます🙏」

セッション「脆弱性から学ぶ Webセキュリティ Part2」

https://speakerdeck.com/hypermkt/study-web-security-from-vulnerability2

  • 脆弱性の怪しい匂いに気付こう
  • 根本的解決>保険的対策
  • ディレクトリトラバーサル対策
    • ファイルパスで判定してるやつとかは怪しい臭い
  • OSコマンドインジェクションの対策
    • シェル呼び出し機能関数を使わない
    • escape shell art
  • セッション管理の不備
    • 攻撃例
      • セッションハイジャック
      • セッションIDの固定化
    • 対策法
      • XXS対策
      • セッションIDを推測困難なものにする
      • セッションIDはクッキーのみで保持する
      • php.iniの確認(デフォルトで🙆‍♂️)
        • session.use_trans_sid = 0 [URLにセッションIDを保持しない]
        • session.use_only_cookies = 1
        • session.use_cookies = 1
      • 認証が成功したら新しいセッションを開始する

 

セッション「REST 6+4の制約」

https://speakerdeck.com/koriym/rest-6-plus-4falsezhi-yue

  • RESTにとって、URIは重要ではない
  • v1とか、バージョニングは含めたらrestではない
  • REST =Hypermedia API
  • クライアントはサーバーが何の言語かしらなくていい
  • キャッシュ スケールのため、🙅‍♀️パフォーマンス
  • RFC7234に対応:Kevinrob/guzzle-cache-middleware

質問の時に、おっしゃられてた「技術に対しての背景を理解しよう」というのが、印象的でした。

自分が使っている言語やフレームワークを作ってくれた人って、相当尊敬してるのに名前知らないなーって痛感したので、もっと歴史とか人物とか関係性とかってスルーしてたので、興味持とうって思いました。(偉人紹介ブログ描こうかな😎)

 

入手品

入手品一覧

  • elePHPant(買ってもらった😆)
  • 電子メモパット(アンケート答えてもらった)
  • メルカリノート、SIMケース、ステッカー(無条件のもらった)
  • スマホスタンド(ちょー便利)、チョコ
  • 粗品タオル
  •  食べログの人になれるやつ(ガチャはずれたけどくれた😆)

 


(新幹線で読むように買ったけど、疲れて10ページくらいしか読めんかった・・・。通勤の肥やしにしよう。)

郡山さんのセッションを聞く前に、この本で予習しておけばもっと理解できたなあって思いました😭

 

 

いろんな方のセッションが聞けたのと、お話もできたのでいい機会でしたー!

次はPHPerKaigi2020

これからももっと勉強して、いいコードかけるようになりたいという気持ちになりました^^

 

\スタッフの皆さん、ありがとうございました🙇‍♂️/

 

SpotifyAPIでクイックプレイリスト作成ツールを作ってみた

 

お久しぶりです。長いことサボってました…😓
ちょっと怠けてる今日この頃です、、
残りの2019年気を引き締めて頑張ります🙌

 

サボってる間、何をしていたかというと、ただただライブに行きまくってました。
ライブのはしごとかもしちゃってました!疲れましたけど、幸せでした😇

行くライブは対バンが多かったので、ライブ前の予習にプレイリストを作ってました。(ライブ後に作ることもありますが)
わたしは横着なので、そのプレイリストを作ることさえ面倒でした。
そこで、アーティスト名を入力するだけで、Spotifyプレイリストを作成してくれるツールを作りましたー!✨

https://dj-kin29.herokuapp.com/

 

ぜひ対バンや小さめのフェス前に、全出演アーティストを入力してサクっとプレイリスト作って楽しんじゃってください✊!!

 

使い方

  1. https://dj-kin29.herokuapp.com/にアクセスし、各項目の入力をする。
    • アーティスト名 ( 必須 ) [5個まで入力可]
    • プレイリスト名 ( 任意 ) [default: dj-kin29-日時]
    • cookie使用の許可 ( 必須 )

  2. (初回のみ)Spotifyログインをし、アクセス許可を同意する。
  3. プレイリスト(非公開)が作成されます!!!
    リンクより、プレイリストに飛ぶことができます。

 

※ アーティスト名検索は、ヒットした一番上のものとするので意図しないアーティストでプレイリストが作成されることがありますので、ご注意ください ⚠️

 

余談ですが、ここで入力したアーティストは、今私がはまっているアーティストさん達です☺️
ぜひ聞いてみてください🎧⚡️

 

使ったもの

参考

 

SpotifyAPIの使い方や、実装内容はまた別記事で書きたいと思います!

 

可変長引数(可変個引数)とは?

 

どうも!

名古屋に越してきてまだ3ヶ月ばかりですが、早くも県内で引っ越すことになりました、面倒ですねええ、引っ越し😩

 

本題

PHP(JSでもみたことあるような気がする)で、

function method(...$params){}

みたいに関数の引数に使われてる「…」があると思うんですが、何してんのか分からないので調べてみました!

 

 

...$params」の正体

調べてみたら、可変長引数(可変個引数)というものだそうです。

引数に「...$params」を含む関数のように、引数が可変する関数ことを可変個引数関数というみたいです。

PHP5.6以降から使用できるようになり、PHP5.5以前の場合は func_num_args()func_get_arg() および func_get_args() で代用するとのことです。

 

参考:https://www.php.net/manual/ja/migration56.new-features.php#migration56.new-features.variadics

 

 

使い方

php.netに聞いてみると、、、

引数リストに … トークンを含めることで、 その関数が可変長の引数を受け取ることを示せます。 引数は、指定した変数に配列として渡されます。

参照:https://www.php.net/manual/ja/functions.arguments.php#functions.variable-arg-list

 

 

使ってみる。

testKahenChoArg.php

<?php

function echoList($listName, ...$items)
{
  echo $listName . PHP_EOL;

  foreach($items as $item) {
    echo '- [ ] ' . $item . PHP_EOL;
  }
}

echoList('引っ越しのtodo', '転出届を出す', '転入届を出す', '免許証の住所変更', 'クレカの住所変更');
echoList('購入リスト', 'カーテン',  'トイレットペーパー');

実行結果

$ php testKahenChoArg.php
引っ越しのtodo
- [ ] 転出届を出す
- [ ] 転入届を出す
- [ ] 免許証の住所変更
- [ ] クレカの住所変更
購入リスト
- [ ] カーテン
- [ ] トイレットペーパー

 

なるほど〜😇引数を配列にして関数に渡してくれるんですね。

引数の数が明確でない時とかに使えそうですね!!!

おそらく使うことはあまりないと思うのですが、フレームワークなどを読んでる時にこの「…」がでてきて何をしているのか分からなかったので、スッキリしました^^

 

npxで電子名刺つくってみた!

 

先週、Nagoya.php#17でLTをしていた方がnpxを使った電子名刺で自己紹介をしていて、

めちゃくちゃカッコよくて真似して作ってみました!

 

 

ターミナルで

$ npx kin29

を打つと以下スクショのように情報がでるようにしました!

追記(2022/09/10):使う機会がないので非公開&削除しました😅

business-card

 

 

仕組み

npx <user-name>を実行すると、

該当のnpmパッケージを落としてきて、package.jsonにある"main": "/bin/card.js"を実行する(テキストファイルをconsole.logする)とのこと。

package.json

{
...
  "main": "/bin/card.js",
  "bin": {
    "kin29": "./bin/card.js"
  },
...
  "scripts": {
    "prepublish": "npm run build",
    "build": "node build.js",
    "dev": "npm run build && node ./bin/card.js",
    "lint": "standard",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

"scripts"にあるように、build.jsを自分用に修正をして、
npm run buildすると、出力ファイルである./bin/outputができます。
npm run dev で、 npx * のシュミレーションができます。

bin/card.js

#!/usr/bin/env node
// 👆 Used to tell Node.js that this is a CLI tool

'use strict'

const fs = require('fs')
const path = require('path')
const output = fs.readFileSync(path.join(__dirname, 'output'), 'utf8')
console.log(output)  // bin/output に出力テキストがある

 

そもそも、npxとは?

公式サイト:https://www.npmjs.com/package/npx

npm5.2.0以上が導入されていれば、npxコマンドも使えるそうです。

指定されたnpmパッケージがローカルに存在しない場合には、インストールをしてコマンド実行するものだそうです。

npmと違うのは、たとえローカルにインストールされていなくてインストールすることになっても、一時的にしかインストールせず実行後は削除されるらしいです。

ローカルを汚さずにすみますね😄

 

npmとnpxを比較してみた💡

● npm

:~/test-npm$ ls //まだローカルには何もない

:~/test-npm$ npm install eslint
...
+ eslint@6.3.0
added 119 packages from 75 contributors and audited 176 packages in 5.246s
found 0 vulnerabilities

:~/test-npm$ ls   //ローカルにインストールされた!
node_modules package-lock.json

:~/test-npm$ node_modules/.bin/eslint --version
v6.3.0

●npx

:~/test-npx$ ls

:~/test-npx$ npx eslint --version
npx: 119個のパッケージを4.678秒でインストールしました。
v6.3.0

:~/test-npx$ ls //ローカルにインストールされてないよ^^

 

npmに公開する

npxを使った電子名刺を公開するためには、npmで公開する必要があります。

やりかた

  1. https://www.npmjs.com/ にアカウントを登録する。
  2. $ npm adduser でログイン(1の登録情報を使う)する。
  3. GitHubリポジトリを作成し、masterにpushする。
  4. $ npm publish でnpmに公開をする。
    // タグをつけてpushする。
    $ git tag -a v1.0.0
    $ git push origin tags/v1.0.0
    
    // npmに公開する。
    $ npm publish ./
  5. npx <user-name> を試して、確認する。

 

さいごに

composerにもnpxみたいな機能ないんかな?って思って、

「composer npx」でググったら、https://github.com/composer/composer/issues/7272

↑でなんか、あるよー的な雰囲気なことを書いてると私の英訳力では感じたのですが、本当にできるのかよくわからんです 😅

 

 

 

参考:

[Qiita]npm 5.2.0の新機能!「npx」でローカルパッケージを手軽に実行しよう

[Qiita]npxでnodeモジュールを実行する

[Qiita]初めてのnpm パッケージ公開

 

GASのユニットテストを書いてみる

お久しぶりです。
ネタが尽きてきたのと、サボってました…

名古屋にきて、名古屋飛ばしはあるものの
宮崎にいた時よりも行きたいアーティストのライブがありふれていて金欠の日々です。
(適度な副業あれば、ください^^)

 

今回の本題に入ります!

7月にテストをきちんと書いているとてもいい会社に転職しました。
フロントエンドでもきちんとテストに向き合っていて刺激的な毎日です。

そこで、わたしの大好きなGASでもテストかけないかなーってふいに思い、
ググってみると、、、、ある!!!

 

その名は、

\  QUnit for Google Apps Script  /

QUnit for Google Apps Script is an experimental fork of QUnit that enables developers to test their Google Apps Script code.

QUnitの実験的なGAS用ユニットテストのようです。
そもそも、QUnitを知らない不束者です…

 

使い方

参考:https://qiita.com/yooo_gooo/items/07c9513a87f6633e40c1

一. QUnitライブラリを追加

qunit/gas/README.md を参考にしてみます。

  1. Select “Resources” > “Manage Libraries…” in the Google Apps Script editor.
  2. Enter the project key (MxL38OxqIK-B73jyDTvCe-OBao7QLBR4j) in the “Find a Library” field, and choose “Select”.
  3. Select the highest version number, and choose QUnit as the identifier. (Do not turn on Development Mode unless you know what you are doing. The development version may not work.)
  4. Press Save. You can now use the QUnit library when writing your tests. You can see a list of available functions by typing QUnit followed by a dot. Alternatively, read the API docs.
  1. スクリプトエディタを開いて、リソース>ライブラリを選択する。
  2. ライブラリを追加の欄に、「MxL38OxqIK-B73jyDTvCe-OBao7QLBR4j」を入れて追加ボタンを押す
  3. QUnitの一番大きいバージョンを選択する。(詳しくない限り、デベロッッパーモードは有効にしない) ※今回はバージョン4を選びました。
  4. 保存ボタンを押下する。これでQunitライブラリを使えるようになりました。使用可能なQunit関数は API docs.を読んで。

QUniyライブラリの追加

 

 

二. テストを書く

README通り、 API docs.>QUnit (version 4) を参考にしました。

function doGet( e ) {
  QUnit.urlParams( e.parameter );
  QUnit.config({ title: "Unit tests for my project" });
  QUnit.load( isPublicHolidayTest );
  
  return QUnit.getHtml();
};

QUnit.helpers(this);

 

/**
 * テストコード
 */
function isPublicHolidayTest() {
  test('isPublicHoliday Test', function(assert) {
    var date = '2019-08-11';
    assert.ok(isPublicHoliday(new Date(date)), date +' は休日');

    var date = '2019-08-20';
    assert.ok(!isPublicHoliday(new Date(date)), date +' は休日ではない');

    var date = '2019-01-01';
    assert.ok(isPublicHoliday(new Date(date)), date +' は休日');
  });
}

 

/**
 * テスト対象の関数
 * (祝日であればtrue、そうでなければfalseを返す)
 */
function isPublicHoliday(data){
  //日本の祝日のカレンダーID
  var holidayCalId = "ja.japanese#holiday@group.v.calendar.google.com";
  var holidayCal = CalendarApp.getCalendarById(holidayCalId);

  return holidayCal.getEventsForDay(data).length > 0
}

 

▼assert.ok(value[, message])

を使ったことがなかったんですが、valueがtrueであれば「okay(message)」をechoするっぽいです。

assert.ok(true);                            //okay
assert.ok(true, 'okokok!!!');      //okokok!!!

参考:https://nodejs.org/api/assert.html#assert_assert_ok_value_message

 

 

三. テストを実行

スクリプトエディタの
公開 > ウェブアプリケーションとして導入 > 「最新のコードでテスト」のリンク
へ飛ぶとテストが実行され、結果がみれます。
※アプリケーションにアクセスできるユーザー:「自分だけ」にできます。

QUnitのテスト結果

 

 

感想

うーん、clasp使って、CIでテストさせたいですよねー
毎回、スクリプトエディタでテスト実行するのは面倒 😄

フロントのテストって書いたことがないのですが、
GASだったらセル依存となると思うので、テストを書くの難しそうだなあと感じました。。。

ラズパイにOSMCを入れてYouTubeを見る、そしてiPhoneから遠隔操作する!

PS3の調子が悪くても、chromecastなんて買わなくても、PCをつながなくても、テレビでYouTubeが見れるんです!
(そのほかにもSoundCloud/AmazonPrime/DAZN…すごい数のサービス有)
そして、テレビのリモコンでも操作できる(※REGZA LINK使用)し、iPhoneでも操作できる!
ラズパイがあれば!!!ラズパイってやっぱすごいなって思いました。

 

 

今回使うものが、

\ OSMC (Open Source Media Center) /

今回は、一般的なRaspbianOSイメージを使わず、OSMC専用イメージを使いました。
(apt-getでの導入も可能らしいです、重すぎて私は断念しました…)

 

kodiなのかosmcなのか、よくわからんくってググるの大変でした。
– ラズパイにいれるOSのイメージ   :OSMC_TGT_rbp1_20190623.img
– 遠隔操作(リモコン)用のアプリ名 :Official Kodi Remote
ですもん…

あ、よく見ればちゃんと書いてました。

https://osmc.tv/about/より
>OSMC (Open Source Media Center) is a free and open source media player based >on Linux. Founded in 2014, OSMC lets you play back media from your local >network, attached storage and the Internet. OSMC is the leading media center in >terms of feature set and community and is based on the Kodi project.

(ざっくり感覚英訳)
OSMCとは、「Open Source Media Center」の略で、
無料のオープンソースメディアプレーヤーだよ、Linuxをベースに作っているよ!
2014年設立、….. OSMCは、….Kodiプロジェクトをベースに作ってるよ!

 

 

使ったもの

– ラズパイ1
– SDカード(16GB)
– キーボード  ←初期設定時のみ必須
– マウス   ←キーボードがあればいらないかも
– HDMI
– デスクトップ(テレビでもできます〜)
– 電源アダプター
– 無線LAN(USBポートでさせるタイプ)

作り方

1.SDカードにOSMCのイメージを入れる

書き込む前にフォーマットする必要があります。
(前回の記事の「1-2. SDにRaspbian(OS)を焼く」を参考にしてください。)

OSMCのイメージがあるところ:https://osmc.tv/download/
(windows/mac用もあります)

 

2. ラズパイにSDカードを差し込んで起動→初期設定

起動すると初回設定画面が出てきます。
ネットワーク設定(Wi-Fi)や、言語設定、TimeZone設定を行います。
初期設定での操作に、マウスとキーボードを使いました。
私は、タイムゾーンはAsia,Tokyoにしましたが、言語設定はEnglish(US)にしました。[理由:かっこいいから]

!!!ポイント!!!
– 日本語の文字化けを直すために、
settings > Interface > Skin より、 Fonts を 「Arial based」にする。
– wifiの接続に成功すると、3. iPhoneをリモコンにするで使うIPが表示されます。
– Setting > Service > Controlより以下の許可を設定する。
Web Server > Allow remote control via HTTP
Application Control > Allow remote control from applications on other systems
↑これをしないと、3. iPhoneをリモコンにするができません。

 

3. iPhoneをリモコンにする

iPhoneで遠隔操作をするために、アプリ「Official Kodi Remote」を使用します。
(Android用もあるらしいです。)

iPhoneのwifi接続を、2で設定したwifiと同じものにしてください。

アプリ「Official Kodi Remote」を開き、
REMOTE CONTROL > Add Hostより、
wifi接続で成功した際でてくるIP(portは80)を入力し、Find Kodiを押下してください。
初期設定で特に設定しなければ、usernameとpasswordは空白でも繋がります。
KodiRemoteの設定画面 

 

4. Video-add-onよりYoutubeを追加

Settings > Add-on browser > install from repository > Video add-onsより、
Youtubeをインストールします。

ここを見ると、多種多様のサービスが導入できることがわかります。
こんなにいっぱいあるの?ってめちゃ夢広がった瞬間でした。

インストールが終わったら、Video > Video add-ons に Youtubeが増えています。
Youtube > Searchとか適当に選ぶと、二段階認証必要ですみたいなアラートが出てくるので、それに従います。
二回コードを入力し終わると、Youtubeが見れるようになります!(Googleアカウントが必要です。)
ラズパイでYouTubeを見る

 

 

メモ

– OSMCのUIがちょっとわかりにくい、特に設定関係の
有効の場合□が明るくなる、無効の場合□が暗い部分とか

– キーボード操作の場合、戻るボタン = エスケープ()
– 初回は音量が小さいので、iPhoneのリモコンから音量あげないと音声が聞こえない

 

 

参考サイト(とっても感謝しています!)

 

 

感想

もうこのラズパイあれば、ほぼAmazonPrime見るためにしか使ってないPS3売っちゃてもいいんじゃないかなって気持ちになりました。

ラズパイってほんとなんでもできますねえ、すごい。