Web開発におけるサーバーサイドプログラミング
何を行っているか
リクエストに応じてさまざまなデータを動的に表示する
静的なテンプレート (HTML, CSS, JavaScript)に表示される情報を動的に更新する
どのように行われるか
DBからデータを読み出してページに表示する
ユーザーが入力したデータをバリデーションする
バリデーションされたデータをDBに保存する
ユーザーの権限をチェックした上でログインさせる
Webサーバとは
「「Webサーバ」はハードウェアまたはソフトウェア、あるいは両方が動作しているものを指します。」
フレームワーク
Web開発で用いられる共通した作業に伴う労力を軽減することを目的とする
データベースへのアクセスのためのライブラリ
テンプレートエンジン
セッション管理
オブジェクトリレーショナルマッパー (ORM)
ex: TypeORM, Prisma
フレームワークによって提供される、データベースの読み取り、書き込み、照会、および削除操作を抽象化するデータベース層
小さなフレームワーク
Express(node.js/javascript) 軽量、シンプルで初めやすい
必要に応じて好みのパッケージを加えれば良い
そのままだと何でもはできない
大きなフレームワーク
Rails(ruby)
MVCフルスタックに開発できる
様々なパッケージが内包されている
フレームワークの使い方がある程度決まっているからルールに沿って開発することで他のRailsエンジニアと共有しやすい
裏で何をやっているか分からないまま開発できてしまう
10年ほど前はフロントとサーバーサイドがごっちゃになって開発されていた
最近ではViewを切り離しAPIモードでの開発がされている
code:app.js
// expressモジュールを読み込み、インスタンスにしてapp変数(appという名前はならわし)に保存する
const express = require('express');
const app = express();
// ルートに対してGETメソッドを投げることで"Hello world"を返している
// サーバーが立っている状態でブラウザからルートにアクセスすればブラウザ上に"Hello world"が表示される
app.get("/", (req, res) => {
res.send('Hello world');
});
const usersData = [
{id: 1, name: 'ichiro'},
{id: 2, name: 'jiro'},
{id: 3, name: 'saburo'},
];
// idによって異なるレスポンスを返す場合
// :をつけることでidは可変値となる
app.get("/users/:id", (req, res) => {
const targetId = req.params.id; // フロント側から指定したidを取得
const found = usersData.find(element => element.id === targetId);
// jsonを返す
res.json(found);
})
// サーバーを立てる時のおきまり
// process.env.PORT で指定されている番号か8000番ポートを使う
const port = pocess.env.PORT || 8000;
app.listen(port, () => {
// サーバーが立てばターミナルに出てくる
console.log(Listening on port: ${port}
});
HTMLのaタグのhref属性にapiのパスを設定すればGETメソッドで叩くことができる
code:html
<a href='/users/1'>IDが1のユーザーの情報を取得する</a>
JavaScript(フロント側)からGETメソッドを叩く
code:js
// users全部を取得する
async function fetchUsers() {
const res = await fetch('/users', { method: 'GET' });
const users = await res.json();
// usersを表示する
console.log(users);
};
// 特定のユーザーを取得する
async function(id) {
const res = await fetch(/users/${id}, { method: 'GET' });
const user = await res.json();
console.log(user)
}
POSTメソッド
HTMLのformタグを介して、サーバーにリソースを送信することができる
リソースを新規作成する
リソースにデータを追加する
code:app.js
app.post('/users/update/:id', (req, res) => {
// リソースを更新する処理
// 成功した場合status201:Createdなど
res.status(201);
});
code:html
// id:1のuserを更新
<form action='/users/update/1' method='POST'>
// 入力フォーム等
</form>
入力フォームに入力したデータがサーバー(/users/update)で待ち受けている処理に送られる
JS(フロント)からPOSTメソッドを叩く
code:js
async function updateUser(data) {
// fetchメソッドにHTTPメソッドの種類を記載する
const res = await fetch(/users/update/${data.id}, {
method: "POST",
data // 更新したい内容
});
console.log(res.status); // 成功していたら200とか
}
分からないこと
JSONを返すWebAPIを作りサーバーを立て、別リポジトリにあるフロントエンドからWebAPIを叩いてCRUDを行う方法
予想:フロントからfetchメソッド(あるいはaxios)を使い、サーバー上のリソースにGET,POST,PUT,DELETEなどのメソッドを用いてアクセスし、返してもらったJSONを整形して表示する。また、リソースデータを更新する場合などは、フロントから送ったデータでの更新をまって、JSONを返してもらい、整形・表示する。
実行:バックエンドサーバーを立てた状態でフロントエンドからAPIを叩く
結果
エラー:CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Cross-Origin Resource Sharing(CORS):オリジン間間リソース共有
セキュリテイ上の理由でブラウザからオリジン間HTTPリクエストが制限されている状態
オリジン
ウェブコンテンツにアクセスするために使われる URL のスキーム (プロトコル)、 ホスト (ドメイン)、 ポート によって定義される
スキーム: http
ホスト: example.com
ポート: 8000
なぜエラーが出たか
フロントエンドJavaScriptで使用したXMLHttpRequestやfetchAPIでは同一オリジンポリシーに従い、アプリケーションが読まれたのと同じオリジンに対してのみリソースのリクエストを行う為
つまりバックエンド()とフロント()ではオリジンが異なる為、フロントから code:js
などしてリソースを取得しようとしても制限されてしまう
(バックエンドだからで定められているいうわけではない) 解決策:ヘッダーにCORSを無効にする記載をする
code:js
// 解決策1.
// ドメイン直下(localhost:3000)にアクセスした時の処理
app.get('/', (req, res, next) => {
res.set({ 'Access-Control-Allow-Origin': '*' }); // ここでヘッダーにアクセス許可の情報を追加
// 何らかの処理
});
code:js
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
*(ワイルドカード)を指定することであらゆるアクセスを許可している
公開するAPIはワイルドカードで問題ないが非公開APIには具体的なドメインを設定する必要がある