前書き
ACCESS Advent Calender 2021 に、 @n2-freevas登場です。
(ちなみにQiitaに何か書くのは初めてです😂 )
この記事の目的は、「svelteとfastapiがどんななのかを教えたい」 というよりも、これを使って「Web初学者に開発経験を与えたい」になっております。
(前後半に分ける予定の) 当記事を見れば、
開発環境をすぐさま用意でき、フロントとバックエンド開発をそこそこ網羅でき、実際に成果物をネットにあげることができます。
そして、それ以降に続く、「各々がやりたい開発」へと導けたのなら幸いです。
前後半の内容は以下の通り
- 前半戦:全体の概要と、フロントエンドの開発・vercelへのデプロイ
- 後半戦:バックエンドの開発と、バックエンド成果物をherokuにデプロイ
また、この記事の方法を使えば、成果物のデプロイはすべて無料でやれます!
(当社AdventCallenderはニッチでおもろい記事が多いので、若干毛色が違くてプレッシャーですが、、、)
とりあえず、当初の目的を失わない程度に、やっていきましょう!
対象
実装についての説明はありますが、言語仕様などのフレームワークと直接関係のない部分は触れません。よって、
- HTML / CSS / JSは触ったことがある
- ここも未経験の方は、
半グレ学生時代の僕も図書館でパソコン片手に読み漁ってエンジニアになることができたこの本を買って、基本を身につけましょう
- ここも未経験の方は、
- Pythonをすでに知ってる or 知らないので、調べつつ触る気概がある
が対象になります!
想定環境
macOS Big Sur ver:11.4
この記事で紹介する内容であれば、Windowsだろうがmacだろうが、さほど違いはないと思ってます。
自分が用意したセットをこのマシンで作ったので、一応参考までに。
あと、ブラウザはChromeを使ってる前提で進めてます。
#前置き・座学など
##なぜ、SvelteKitと、FastApiなのか。
そもそも、なぜこの組み合わせで記事を2本も書くかというと、
こやつらが、今までの開発の中でダントツに簡単だったから、なんですね。
そして、これらを組み合わせとして紹介することで、いいWeb教材になる気がしたからです。
それはつまり、コイツらを使ってWeb開発へ片足突っ込むことが、Web開発の登竜門として最も最適なんじゃないかという仮説に基づいています。
##使う技術について
タイトルでも述べている通り、使う技術を一通り紹介します。
知っているフレームワークは割愛してOK!
Svelteとは?
svelteとは...(矢印押して、OPEN!)
フロントエンドをなんとなーく知っている人は、多分↓のロゴを見たことがあるかもしれない これらは、昨今のフロントエンド開発で主流になっているフレームワークです。Svelteは、これらのメジャータイトルに比べ歴史が浅いですが、結論からいうと、このライバルを蹴散らして主流に躍り出るポテンシャルを秘めた、すさまじい開発体験を与えてくれるフロントエンドの手段です。
また、Svelteをベースにフレームワーク化を施したSvelteKitは、[2021/3](https://svelte.dev/blog/sveltekit-beta)にbe-taが公開され、現在も利用することができます。
SvelteKitは、実際に実務で使っている有名企業も続々登場していることもあり、もしかしたら5年後とかには? 「svelteの経験は?」と面接で聞かれる時代になるかも
* ソースコードはReactよりも遥かに短いソースコードで書ける * svelte固有の構文が少ない。JSを知っていればだいぶ有利。 * (プラグインなどいるが)SSA、SPA両対応 * ソースのディレクトリ構造が、そのままURLの階層構造になるシンプルさ * 動作がはやーーーーい! * 「状態管理」と呼ばれる処理を、めっちゃ楽に書ける
筆者が盲目化していることもあり、メリットしかあげてませんが、今回は、このSvelteKitを激推しで使っていきます!
FastAPIとは?
fastapiとは...(矢印押して、OPEN!)
Pythonというプログラミング言語ほぼ100%のWebAPIフレームワーク。まず、Pythonという言語はそれ自体が、そこそこ早く、書き心地がよく、日本語のドキュメントが揃っているので、初心者にうってつけの言語です。
FastAPIというのは、2018,19ごろに登場した若手で、Pythonでサーバのソースコードがスラスラと書けて、WebAPIに欲しい機能や実装が比較的簡単に導入できるのでおすすめです。
Ruby (on Rails)や、phpをサーバーで実装する事例や、それらへの太鼓判も
他言語のサーバ実装言語対抗馬として、「Go」や「node.js」があります。特に「Go」は、注目言語ということもありめっぽう熱いですが、初心者に優しいドキュメントの数で言うとPythonに軍配が上がるので、この記事ではFastAPIを選択します。
また、自他ともに、「node.jsやGoに匹敵する速さ」という評価を下していで、僕もそう感じています。
pythonのFlaskを知っている人は、多分FastAPIのことを一瞬で理解できますので、そういう人は、なおのことお勧めです。
vercelとは?
svelteのソースコードをデプロイするときに使います。ムチャ楽です。
herokuとは?
FastAPIをデプロイするときに使います。ムチャ楽です。
(ただ、もし、あなたのアプリケーションが、10万・100万人が使うようなデカイアプリケーションになったら、herokuの弱点が露呈してくるので、大人しくAmazon Web Serviceを使うことをお勧めします。)
###その他
なお、今回は初心者向け記事ということで、Dockerを使わないこととします。
理由としましては、Dockerを使う種々のメリットより、開発体験を妨害するデメリットの方が多いと判断してのことです。
アプリケーションの構成
初学者の方は一度足を止めてください!
今回のアプリケーションは、王道中の王道である「Restfulな」「JSON形式の」アプリを目指します。
上図が、王道中の王道の構成であるRestfulなアプリケーションの構成図です。
Restfulアプリは、WebAPIというものが軸になって、いろんな物事を進めていきます。
世の中にあるほとんどのアプリケーションは、デバイス単体で完結しない機能を有していることがほとんどです。(例えば、他の人と交流する機能とか。)
それを実装するときには、通信を行って情報を補完していきます。
通信の登場人物は、たいていサーバと、フロントエンド(PC・スマホ)、そしてプロトコル (情報の送信方法)です。
サーバは「情報の生成や整理をして、それをフロントに送る役割」、フロントは「その情報を人に魅せるための処理 & ユーザの操作をサーバに送る処理」 というふうに役割分担しています。
その「情報」というのはどうやって送る? それはたいてい、HTTPSというプロトコルを使い、HTTPS通信にjsonと呼ばれる形式の情報体を格納して送ります。そして、APIというのは、フロントがサーバからそのjsonを得たりするために作られる窓口的な存在なのです。
百聞は一見にしかず。とりあえずAPIを叩いてみよう。
世の中にAPIは星の数ほどありますが、、、、
下図は、catAPIという高尚な趣味をしたAPIを叩くと得られるjsonです。
(世の中には、猫画像をデータベースにコレクションしている尊大な猫愛の持ち主がいて、そのお方はあろうことか、自分のコレクションをwebAPIを配備して全世界に公開したのです。)
このAPIは特にセキュリティ的な壁を用意していないフリーのAPIなのでどんな輩でも叩き放題です。
試しに皆さんも、叩いてみましょう。上のような情報体が取得できます。
APIを叩く方法も星の数ほどありますが、今回は、Talend API Testerを使います。リンクの指示に従い、Chromeに拡張機能を入れて、起動して、
https://api.thecatapi.com/v1/images/search?limit=3
と打ち込んで、Send を押しましょう。すると、先程の画像のようなjsonが帰ってきます
catAPI公式ドキュメントを見ると、/search
の後にlimit
やpage
などと付加情報を与えると、jsonの返り方が変わってくるらしいですよ。
これらは当然、catAPIの実装者が決めているAPIのルールです。
そして、我々はドキュメントなどに書かれている、そのルールにしたがってコマンドを叩くことで、情報を得られるのです。
では、こういう風に作られたAPIというものを、あなたが思うようにサーバに実装して、それをあなたのアプリ自身が叩いて、そしてその情報を元に、アプリの魅せ方を変えるWebページを組んだらどうなるでしょう。
もうわかりましたね。
やりたいことは、単純にそういうことなのです。
それが、Webアプリケーションの全てです。
準備
お手間ですが、homebrew, node.js、 python3を用意してください。
以下の記事に従えば、できます!
初学者の方にとって、この事前準備は苦しいものになるかもしれません。私からは誠悦ながら、この事前準備のゴールを示しておきます。
インストール作業が終わったら、以下のコマンドを打って、以下のように出てこればOKです。
$brew --version
Homebrew 3.3.5 (これ)
Homebrew/homebrew-core (git revision 0eb6718c519; last commit 2021-11-29)
Homebrew/homebrew-cask (git revision bec9ce12ba; last commit 2021-11-29)
$ npm --version
6.14.13 (これ)
$ python3 -V
Python 3.8.12 (これ)
テンプレートで学ぶ
では、基礎的なAPIの挙動を楽しめるアプリを作ってみましょう。
僕が用意したテンプレート↓があるので、まずこれで遊びましょう。githubからダウンロードしてくださいな!
ダウンロードの流れ↓
とりあえず起動してみる。
svelte-sample 側の、ディレクトリ上で、
// 必要なライブラリのインストール
// (予めpackage.json/dependenciesに定義しておいたライブラリを自動で全部installする。)
// (SvelteKitなども含まれている。)
$ npm install
// SvelteKitの起動
// (package.json/scripts/dev に書いてあるコマンドを打ったのと同義)
$ npm run dev
すると、上記のような回線が開くので、
http://localhost:3000
をブラウザでアクセス
はい、これだけ!
Svelteの主要機能を理解する
ファイルの書き方
.svelte 拡張子で終わるソースが、svelteのソースコードです。下図は、/src/routes/menu-a/index.svelte
のソースです。
//javascript実装部分
<script>
</script>
//それ以外のマークダウンの部分
<h1>MENU A</h1>
//CSS実装部分
<style>
h1{
line-height: 70vh;
text-align: center;
}
</style>
基本的に、svelteは、
-
scriptタグ
で囲まれた、javascript実装部分 -
styleタグ
で囲まれた、CSS実装部分 - それ以外のマークダウンの部分
の3つで構成されています。(ちなみに順不同でよかったはず)
また、script
とstyle
には、lang='***'
と記載すれば、typescriptや、scssなどの拡張言語に変更することもできます。
共通部分の書き方
昨今のWebページは、共通部分があることがほとんどです。
例えば、/src/routes/cat/index.svelte
が出力する以下のページをご覧ください。
http://localhost:3000/cat
(注: もしcatApiにアクセスできない状況だと、ここで何もうつりません。もしもの対策も用意したので↓をやっとこう。)
$catsStore = await getCats(10) //もしこれがだめだったら、
//$catsStore = await getCatsMock()
//$catsStore = await getCats(10)
$catsStore = await getCatsMock() //これを使おう
このページは、
- ヘッダーなどの、ページの外枠的なレイアウトを決めている部分
- 猫の画像が並んでる部分の、1つ分のパーツ
は、共通化しています ( 要は、同じソースコードをなんべんも書かんでいいようにしている。 )
前者は、「どのページでも使い回す」 素材です。
これは、__layout.svelte
に実装されています。
svelteでは、__layout.svelte
と命名されたソースが、/routes
直下にある時、そのソースを全てのページの共通パーツとして認識します。
https://kit.svelte.dev/docs#layouts
そして、__layout.svelteの任意の部分に<slot/>
を記載します。
すると、各ページのマークダウンは、この<slot/>
以下に描画される扱いを受けます。
猫の1パーツは、俗に「コンポーネント」と呼ばれる単位です。コンポーネントを実装はとても簡単です。まず、
- src配下のどこかに、.svelteファイルでパーツを実装。( 当サンプルでは、
/src/lib/component/
以下に記載し、$lib/component/...
とすればimportできるように設計してあります。 ) -
import CatApiComponent from '$lib/component/Home/CatApiComponent.svelte'
といった具合で、コンポーネントをインポート -
<CatApiComponent 引数.... />
と、マークダウンの部分に記載。
//コンポーネントの実装
<script lang='ts'>
import type {CatModel} from '$lib/model/Cat'
....
// 補足:export let と書いておくと、コンポーネントは引数を受け付けるようになる。
export let cat: CatModel
//コンポーネントを呼び出す側の実装
<script lang='ts'>
import CatApiComponent from '$lib/component/Home/CatApiComponent.svelte'
....
// cという変数を、引数で用意したcatに渡すと、コンポーネントに情報を渡すことができる!
<CatApiComponent cat={c} on:catLoveLove={catLoveLoveHandler}/>
終わりです。
フロント初学者の方は、ここで、デベロッパツール等を使い、サンプルのソースが、実際にブラウザにどう乗っかってくるのか観察すれば、やっていることがよりわかるはずです!
ルーティング
基本的に、svelteソース1枚が、ページ1枚になります。そして、すでにお察しの方もいるかもしれませんが、
.svelteファイルの名前・ディレクトリそのものが、ページのURLになります。
注:
( index.svelteは、それが属する 「フォルダの名前」 がURLになります。 )
( 「__」 (アンダーバ2つ) がファイル名についているフォルダ・ファイルは、ルーティングから無視されます。 )
例えば、
このサンプルは、上記のような構成をしているので、
- http://localhost:3000
- http://localhost:3000/cat
- http://localhost:3000/cat/{id} ( {id} には、URLセーフならなんでも受け付ける )
- http://localhost:3000/menu-a
- http://localhost:3000/menu-b
- http://localhost:3000/menu-c
- (__layout は無視。)
これらがURLとして開放されます。
マークダウン部分の制御構文
サンプル内には、{#each}
や{#if}
などの、制御構文が登場します。
svelteは 今あげた2つである「(簡易的な)ループ」と 「条件分岐」 しかありませんが、これらで、マークダウン部分を制御することができます。
https://svelte.dev/tutorial/if-blocks
ストア
svelteに限らず、こういうフレームワークでは、ファイル間を跨いだ処理を書きたい時に難儀するものです。その点、svelteはここがすごい強いと感じます。
上図は、svelteに搭載されている「跨ぎ」の機能一覧と動作の抽象図です。
先ほど紹介した<slot/>
も、跨ぎの一種です。
跨ぎに関しては色々ありまして、その場その場で最適なものがあります。が、「とりあえず使っとけ」と推したいのはstoreです。
storeは、あなたが作ったアプリケーションが、ブラウザで表示され続けている限り、あらゆる変数の値を保存し、どの画面でも共有することができる機能で、フロントエンドの主要な概念になります。
そして、svelteを推したい最大の理由は、このstoreへの書き込み/読み込みが猛烈に楽だからです。
storeを使っている実装は、簡単ですがsampleにあります。
// storeのための「モデル」の宣言。catAPIから得られる猫モデル
export interface CatModel {
breeds: []
height: number
id: string
url: URL
width: number
/* catAPIの返却値サンプル
breeds: []
height: 1024
id: "c92"
url: "https://cdn2.thecatapi.com/images/c92.jpg"
width: 784
*/
}
import { writable } from 'svelte/store'
// さっき作った 猫モデルをimport
import type { CatModel } from '$lib/model/Cat'
// 猫モデルの配列[]を、storeが読み書きできるように定義し、その結果をcatsStoreに代入
export const catsStore = writable<CatModel[]>([])
これにて、catssStore
という変数が、あらゆる.svelteファイルで読み書き可能になりました。
試しに、読み取りを行っているソースが以下のソースだ。
catsStore
をインポートし、
<script lang="ts">
...
import { getCats } from '$lib/api/catApi'
import { catsStore } from '$lib/store/CatStore';
import { onMount } from 'svelte';
...
onMount( async()=>{
//storeへのアクセスは、「$」マークをつける。
if($catsStore.length == 0){
//getCats関数(自作)が、catAPIで10匹の猫を取得するので、catsStoreに代入(書き込み)
$catsStore = await getCats(10)
//catsStoreのコンソール表示(読み込み)
console.log($catsStore)
}
})
//ストアをマークダウン部分でも使え、catsStoreが変更されたら、この部分も連動して変更される。
{#each $catsStore as c, i}
<CatApiComponent cat={c} on:catLoveLove={catLoveLoveHandler}/>
{/each}
といった具合で、さながら普通の変数のように扱える。これがどれだけ脅威的かは、人によるだろうが、少なくとも既存のフロントエンドエンジニアはsvelteのstore機能の簡単さには、結構驚かされた。。。
storeは大抵の場合object
かarray
なので、↓あとは、このあたりの仕様を理解していれば、storeの操作でつまづくことはないでしょう。(体験談)
dispatcher
storeが強力すぎるので、霞んでしまいがちだが、dispatcherは、コンポーネント間共有においては、同様に強力。
dispatcherが使えるシチュエーションは限られていて、あるコンポーネントが親に何か伝えたいときに使うモジュールです。
サンプルだと、/cat/index.svelte
と、そこが呼び出しているCatApiComponent
で使われている。
<script lang='ts'>
import type {CatModel} from '$lib/model/Cat'
//dispatcherの定義
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
export let cat: CatModel
function onClickHandler(){
//こんな具合で、親に何を伝えたいかを定義。
dispatch('catLoveLove',{
id: cat.id
})
}
</script>
// 補足:エレメントにon:ナントカ と書くと、そのエレメントに、ナントカの動作をしたら〜する、を実装できる。
// この場合は、「クリックしたら onClickHandlerを実行 」ができる。
<article on:click={onClickHandler}>
<section class='components-box'>
<script lang="ts">
import CatApiComponent from '$lib/component/Home/CatApiComponent.svelte'
import { goto } from '$app/navigation';
...
function catLoveLoveHandler(event: CustomEvent){
//svelteの、gotoモジュールを使って、localhost:3000/cat/{id}へジャンプ
goto(`/cat/${event.detail.id}`)
}
...
//ここで、「on:定義したdispatcherの名前」とすると、子供の連絡を受け取る体制が取れる。
<CatApiComponent cat={c} on:catLoveLove={catLoveLoveHandler}/>
上記の例は、サンプルでdispatcherを使いたいがために用意したゴミコードなので、若干魅力が伝わりづらいかも。
(やるなら普通に、猫コンポーネントがgotoすれば、いいよね。)
dispatcherは、コンポーネントに何個でも置けるので、コンポーネントが多くの機能を内包する場合は、強力な機能である。
API叩く部分
このサンプルの/cat
は、catAPIを叩いて、猫の画像情報などを取得し、それをコンポーネントに当てはめ表示している。
svelteとは関係ないが、APIを叩く部分をある程度用意しておいたので、見ていこう。
import axios from 'axios' //(API叩くライブラリ)
import type { CatModel } from '$lib/model/Cat' //猫モデルをここでも使います。
// catApiを叩くことしか脳のないcatApiオブジェクトを定義
const catApi = axios.create({
baseURL: "https://api.thecatapi.com/v1",
headers: {
'Content-Type': 'application/json',
},
})
//catApiをREST APIの 「GET」メソッドで送信する関数の定義。
const cat_get = async (url, request?) => {
const res = await catApi.get(url, { params: request })
return res.data
}
// catApiの/image/search APIを叩く関数
export const getCats = async (limit:number = 3): Promise<CatModel[]>=> {
try{
// @ts-ignore
let data: CatModel[] = await cat_get('/images/search',{limit})
console.log(JSON.stringify(data)) //受け取ったデータを、デベロッパツールで見てみよう。
return data
}
catch (error) {
throw error
}
}
ちなみに、サンプルでは、easytoast (自作。svelte-toastのラッパ)を使って、トーストを表示するようにしておきました。下図の、右上に出てきてるやつですね。
また、/src/lib/api/api.ts
に、後半戦で作るバックエンドに繋ぐためのAPI処理部分を用意してあります。ほとんど同じ作りだけどね。
### その他にも...
このサンプルで最も複雑なことをさせている部分は、多分__layout.svelteです。
- ヘッダーを表示する
- ヘッダーのナビゲーションを行う
- ヘッダーのフレキシブルレイアウト
- スマホ版のレイアウト(横幅700px以下)の時の、ハンバーガメニューの実装
- スクロールイベントを起こすと、ヘッダーを勝手にしまう処理
- あとisometricなロゴ(自作で著作権フリーだよ)
このソースでは、これらの機能を実装するために、いくつかsvelteの助けを得ています。
例えば、
<MediaQuery query="(min-width: 701px)" let:matches>
{if matches}
...
{/if}
</MediaQuery>
↑ MediaQueryタブは、外部モジュールのsvelte-media-query
を使ってます。これは、フレキシブルレイアウトを実現する手段の一つです。これはCSSのメディアクエリ機能とほぼ同じですが、フレキシブル化の際に、表示したい要素を増減させたいときに強力な機能です。
<svelte:window on:scroll={scrollEvent} bind:scrollY={scrollY}/>
↑ これは、svelteが用意したwindowインターフェースのラッパみたいなもので、windowのイベントを検知して、指定した関数を発火してくれます。
<header class='{isHideHeader ? 'hide':''}'>
(2021/12時点で、Qiitaにsvelteの言語指定がないので、エラー下線部が出ててごめんね)
↑ svelteのマークダウン部分では、こんな感じで、三項演算子を使って、その要素にクラスを付与するか否かの実装もできます。これは、CSSアニメーションの達人たちにとって非常に強力な機能です。
## 他のことをやらせてみよう
menu-a, menu-b, menu-c
は、空きのファイルにしてある。
ここまでの機能は、実務でも普通に使うレベルの実装なので、これらの機能を使って、何か作ってみましょう!!!
デプロイ
ここまでの実装を、vercelにデプロイして、世界に公開しよう。
## アカウント作成
vercelの公式のサービスサイトから、ログインしましょう。特別な理由がないなら、課金はしなくていいです。
https://vercel.com/
また、githubのアカウントがない方はここで作ってね
https://github.com/
githubにソースをあげる
作ったソースを、githubにあげましょう。
間違ってn2-freevas/svelte-sample
に上げないでくださいネ
わからん人のための手順
特にgitで色々操作していない人は、プロジェクトのディレクトリの .gitは消しとこう。 (人によっては、ここの設定が、```n2-freevas/svelte-sample```を見たままなので、手っ取り早くやるなら消したほうがいいです) ![スクリーンショット 2021-12-11 18.20.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1401757/1c7ad5eb-316a-c9c0-acbf-ae3b1032b6e4.png) github公式サイトへ行き、Repositories の、New をクリック。 手順に従い、リポジトリを作成。(Private, Publicどっちでも可) ![スクリーンショット 2021-12-11 18.23.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1401757/09acd93f-c5bb-8296-3c04-a2139ad447e6.png) リポジトリを作れたら、以下のような画面が現れるので、自分のPCのコマンドライン/ターミナルで、コマンドをペチペチ。 ![スクリーンショット 2021-12-11 18.24.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1401757/32017361-152c-6e85-0e79-698e76b8d551.png) そうしたら、プロジェクトを自分のgithubにあげれます。プロジェクト作成
ログインが成功したら、下図のような、ダッシュボードの「New Project」から、
Adjust GitHub App Permissions →をクリックして、githubの特定のリポジトリと、vercelを連携する。
リポジトリを選択してSaveしたら、vercelに戻るので、連携したリポジトリをimport
そのままDeploy でOKです。
(ちなみに、ここのbuild作業は、ローカルでも確認できます。($ npm run build
)
ローカルのこれが通らないなら、基本的にvercelでも通らないので、注意してください。
また、本サンプルはvercelにあげるための設定をしているので、それを変更しない限りは、
他のデプロイサービスではデプロイに失敗します。
デプロイに成功すると盛大に紙吹雪が舞った後、いくつか進むと以下のような画面に入ります。
はいもう勝ち確です。「Visit」を押すか、DOMAINSに書かれているドメインをコピーして、
https://{ドメイン} で、デプロイしたソースが見れます。
(Vercel、簡単すぎて怖いよね)
この方法でgithubと連携しておけば、githubにソースをあげたら、vercelに勝手にデプロイされます。
もし不都合があれば、設定を変えておこう。
前半戦、終わり
お疲れ様でした!!!!!!
(あとがきは、後半戦でやることとしましょうかね。)
今回紹介した機能以外にも、svelteにはさまざまな機能がありますし、svelteを介して深く掘っていけば、node.jsの理解も深まり一石二鳥です。
svelteで、素晴らしいWebフロントエンジニアを目指しましょう。
良い開発体験があることを願っております、では、後半戦でまたお会いしましょう!
後半戦は これだ !↓
https://qiita.com/n2-freevas/private/f5114ebf5846031f3c8d