20200114のNode.jsに関する記事は5件です。

NPMでSUDOを回避する技

UbuntuにNodeJSをインストールしたらまさかの不便さに遭遇

先日UbuntuにNodeJSやらNPMをインストールしたところ
グローバルにモジュールをインストールしようとしたら失敗しました。

sudoで実行すればインストールできたのですがGatsby.jsのチュートリアルをやっていたときに

  • 遭遇したエラーの一部
gyp ERR! stack Error: EACCES: permission denied, mkdir '/home/【ユーザー名】/scotch-blog/node_modules/sharp/build'

このエラーが発生したときに
NodeJSをまたインストールしないといけないのかなと暗い気持ちになっていましたが、以下の方法でnpmパッケージをインストールするディレクトリを指定することで事なきを得ました

以下はそのやり方を共有します

グローバルなモジュールをインストールするディレクトリは指定できる!!

元ネタのリンク

以下にエラー回避をマニュアルでやる方法をお伝えします

1. $HOMEのディレクトリにnpmのモジュール格納用ディレクトリを追加する

 mkdir ~/.npm-global

2. npm set configで今作ったディレクトリを指定する

 npm config set prefix '~/.npm-global'

3. ~/.profileで環境変数を追加する

 export PATH=~/.npm-global/bin:$PATH

4.$PATHを更新する

 source ~/.profile

以上です。お疲れさまでした。
元ネタのリンクではそのほかにもnvm
を使った方法などを紹介しています。
NodeJSのバージョン管理ができる代物なので時間があればそちらにも挑戦したいところです。

更新履歴

  • 2020/1/14 新規作成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NPMでsudoを回避する技

UbuntuにNodeJSをインストールしたらまさかの不便さに遭遇

先日UbuntuにNodeJSやらNPMをインストールしたところ
グローバルにモジュールをインストールしようとしたら失敗しました。

sudoで実行すればインストールできたのですがGatsby.jsのチュートリアルをやっていたときにGatsbyのプロジェクトを作成しようとしてエラーが発生しました

以下遭遇したエラーの一部

gyp ERR! stack Error: EACCES: permission denied, mkdir '/home/【ユーザー名】/scotch-blog/node_modules/sharp/build'

このエラーが発生したときに
NodeJSをまたインストールしないといけないのかなと暗い気持ちになっていましたが、以下の方法でnpmパッケージをインストールするディレクトリを指定することで事なきを得ました

以下はそのやり方を共有します

グローバルなモジュールをインストールするディレクトリは指定できる!!

元ネタのリンク

以下にエラー回避をマニュアルでやる方法をお伝えします

1. $HOMEのディレクトリにnpmのモジュール格納用ディレクトリを追加する

 mkdir ~/.npm-global

2. npm set configで今作ったディレクトリを指定する

 npm config set prefix '~/.npm-global'

3. ~/.profileで環境変数を追加する

 export PATH=~/.npm-global/bin:$PATH

4.$PATHを更新する

 source ~/.profile

以上です。お疲れさまでした。元ネタのリンクではそのほかにもnvmを使った方法などを紹介しています。NodeJSのバージョン管理ができる代物なので時間があればそちらにも挑戦したいところです。

更新履歴

  • 2020/1/14 新規作成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DynamoDBのテーブルデータをNodejsでS3にBackupする

はじめに

DynamoDBに大量にあるテーブルのデータを一括でS3にバックアップしたい。。みたいな状況があったので、メモとして書いておきます。

ちなみにテーブルが少量であれば、Data Pipelineを使って簡単に出来ます!!
aws-sdkではData Pipelineの細かいオプションは設定出来なかったようなので、nodejsでData Pipelineを操作することはしていません。

環境

  • Nodejs v11.1.0
  • DynamoDB

事前準備

バックアップを行うためにS3に専用のバケットを作成しておいてください。
この記事ではbackupsというバケットを作成したという例で進めます。

プロジェクトを作成

適当ですが、dynamodb-backuperみたいなディレクトリを作成して進めていきます。

$ mkdir dynamodb-backuper

$ cd dynamodb-backuper

$ npm init

$ npm install aws-sdk dynamodb-backup-restore --save

$ touch export.js restore.js

export.js

export.jsはその名通りDynamoDBから全テーブルのbackupを行うファイルです。

'use strict'

const AWS = require('aws-sdk')
const DynamoDB = new AWS.DynamoDB({region: 'ap-northeast-1'})

async function main(){
    let tables = await getAllTableLists()
    tables.forEach((v) => {
        exportToS3(v)
    })
}

// 実行
main()

// Get all table names from DynamoDB
async function getAllTableLists() {
    let params = {}
    let tables = []

    while(true) {
        let response = await DynamoDB.listTables(params).promise()
        tables = tables.concat(response.TableNames)

        if (!response.LastEvaluatedTableName) {
            break
        } else {
            params.ExclusiveStartTableName = response.LastEvaluatedTableName
        }
    }
    return tables
}

// Function to perform backup
function exportToS3(tableName){
    const Backup = require('dynamodb-backup-restore').Backup
    let config = {
        S3Bucket:     'backups', // 必須 - バケット名 
        S3Prefix:     tableName, // 任意 - 保存するS3のサブフォルダ名
        S3Encryption: 'AES256', // 任意 - 暗号化
        S3Region:     'ap-northeast-1', // 必須 - リージョン
        DbTable:      tableName // 必須 - エクスポートするテーブル名
    }

    let backup = new Backup(config)
    backup.full()
}

以下でエクスポートを実行出来ます。

$ node export.js

restore.js

restore.jsもそのままですが、export.jsでS3にエクスポートしたデータを今度はDynamoDBの指定のテーブルにインポートします。

リストアを行う前に事前にインポートするテーブルを作成しておく必要があります。
今回はnewTest1というテーブルを作ったとして進めます。
この時に注意が必要なのが、データ量によっては無料枠ではキャパシティーレベルが超えてしまうため、データサイズに応じてオンデマンドに変更してください。

以下のコードでは、execRestore関数の第一引数にS3にバックアップをとったtest1というサブフォルダを指定し、インポート用に作成したnewTest1というテーブル名を第二引数に設定します。

'use strict'

function execRestore(bucketName, tableName){
    const Restore = require('dynamodb-backup-restore').Restore
    let config = {
        S3Bucket:   'backups', // 必須
        S3Prefix:   bucketName, // 任意
        S3Region:   'ap-northeast-1', // 必須
        DbTable:    tableName, // 必須
        DbRegion:   'ap-northeast-1', // 必須
    }

    Restore(config)
}

// 実行
execRestore('test1', 'newTest1')

以下でリストアを実行出来ます。

$ node restore.js
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS APIGateway/LambdaとJavascriptで簡易問い合わせサイトをつくる

概要

問い合わせフォーム(javascript) ⇒ APIGateway ⇒ Lambda(Node.js) ⇒ Lambda(Node.js) の流れで簡単な問い合わせサイトを作ります。
contact_form.png
一応レスポンシブにします。
contact_form2.png
バリデーションもあります。
contact_form3.png
contact_form4.png

index.htmlのコーディング

index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <link rel="stylesheet" href="style.css" />
  <title>問い合わせ</title>
</head>

<body>
  <div class="header">
    <a href="#" class="logo">Hoge Hoge Company</a>
    <a class="active" href="#">Home</a>
  </div>

  <main class="main-container">
    <h2>問い合わせフォーム</h2>
    <div class="container">
      <form id="form">
        <div class="row">
          <div class="col-20">
            <label for="name">名前</label>
          </div>
          <div class="col-80">
            <input type="text" id="name" name="name" placeholder="Your name.." />
          </div>
        </div>
        <div id="name-alert" class="alert-message" hidden>入力値が不正です。</div>
        <div class="row">
          <div class="col-20">
            <label for="email">E-Mail</label>
          </div>
          <div class="col-80">
            <input type="email" id="email" name="email" placeholder="Your E-Mail.." />
          </div>
        </div>
        <div id="email-alert" class="alert-message" hidden>入力値が不正です。</div>
        <div class="row">
          <div class="col-20">
            <label for="dept">所属</label>
          </div>
          <div class="col-80">
            <input type="text" id="dept" name="dept" placeholder="Ex: Example Co., Ltd." />
          </div>
        </div>
        <div id="dept-alert" class="alert-message" hidden>入力値が不正です。</div>
        <div class="row">
          <div class="col-20">
            <label for="body">内容</label>
          </div>
          <div class="col-80">
            <textarea id="body" name="body" placeholder="お気軽にお問い合わせください。" style="height:200px"></textarea>
          </div>
        </div>
        <div id="body-alert" class="alert-message" hidden>入力値が不正です。</div>
        <div class="row">
          <button id="submitBtn">送信</button>
        </div>
      </form>
    </div>

    <!-- The Modal -->
    <div id="myModal" class="modal">
      <!-- Modal content -->
      <div id="modal-content">
        <span class="close">&times;</span>
        <p id="result"></p>
        <p id="detail" style="font-size: small;"></p>
      </div>
    </div>
  </main>
  <script src="main.js" defer></script>
</body>
</html>

CSSのコーディング

style.css
* {
  margin: 0;
  padding: 0;
  font-family: "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ Pro W3", "メイリオ",
    Meiryo, "MS Pゴシック", sans-serif;
}

/* Style the header with a grey background and some padding */
.header {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-between;
  background-color: #000000;
  padding: 20px 10px;
}

/* Style the header links */
.header a {
  color: #f2f2f2;
  text-align: center;
  padding: 12px;
  text-decoration: none;
  font-size: 18px;
  line-height: 25px;
  border-radius: 4px;
}

/* Style the logo link (notice that we set the same value of line-height and font-size to prevent the header to increase when the font gets bigger */
.header a.logo {
  font-size: 25px;
  font-weight: bold;
}

/* Change the background color on mouse-over */
.header a:hover {
  background-color: #ddd;
  color: black;
}

/* Style the active/current link*/
.header a.active {
  background-color: dodgerblue;
  color: white;
}

/* Add media queries for responsiveness - when the screen is 500px wide or less, stack the links on top of each other */
@media screen and (max-width: 500px) {
  .header {
    justify-content: center;
  }
  .header a {
    padding: 12px;
  }
}

.main-container {
  width: 90%;
  margin: auto;
}
.main-container h2 {
  margin-top: 12px;
}

/* Style inputs, select elements and textareas */
input,
textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
  resize: vertical;
}

.alert-red {
  border: #ff4500 2px solid;
}

.alert-green {
  border: #00ff7f 2px solid;
}

.alert-message {
  color: #ff4500;
  font-size: small;
  text-align: end;
  margin-bottom: 10px;
}

/* Style the label to display next to the inputs */
label {
  padding: 12px 12px 12px 0;
  display: inline-block;
}

/* Style the submit button */
#submitBtn {
  background-color: #4caf50;
  color: white;
  padding: 10px 18px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 15px;
  float: right;
}

/* Style the container */
.container {
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}

/* Floating column for labels: 25% width */
.col-20 {
  float: left;
  width: 20%;
  margin-top: 6px;
}

/* Floating column for inputs: 75% width */
.col-80 {
  float: left;
  width: 80%;
  margin-top: 6px;
}

/* Clear floats after the columns */
.row:after {
  content: "";
  display: table;
  clear: both;
}

/* Responsive layout - when the screen is less than 600px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
  .col-20,
  .col-80,
  #submitBtn {
    width: 100%;
    margin-top: 0;
  }
}

/* The Modal (background) */
.modal {
  display: none; /* Hidden by default */
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0, 0, 0); /* Fallback color */
  background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
}

/* Modal Content/Box */
#modal-content {
  background-color: #fefefe;
  margin: 15% auto; /* 15% from the top and centered */
  padding: 20px;
  width: 80%; /* Could be more or less, depending on screen size */
}

.request-loading {
  border: 1px solid #888;
}

.request-success {
  border: 1px solid #00ff7f;
}

.request-fail {
  border: 1px solid #ff4500;
}

/* The Close Button */
.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}

javascriptのコーディング

変数URLはAPIGatewayで発行してから実装します。

main.js
const URL = 'https://'; // APIGatewayで作成したURL

const LOADING = '処理中...';
const RESULT_OK = 'リクエストを受け付けました。';
const RESULT_OK_DETAIL =
  "正常に処理が完了すると 'support@hogehoge.com' からメールが配信されます。";
const RESULT_NG = 'リクエストの受付に失敗しました';
const RESULT_NG_DETAIL =
  '大変申し訳ありません。担当者へ直接お問い合わせください。';
const DOMAIN = '@sample.com';
document.getElementById('email').value = DOMAIN;

(() => {
  const modal = document.getElementById('myModal');
  const modalContent = document.getElementById('modal-content');
  const sendBtn = document.getElementById('submitBtn');
  const span = document.getElementsByClassName('close')[0];
  const result = document.getElementById('result');
  const form = document.getElementById('form');
  const nameAlert = document.getElementById('name-alert');
  const emailAlert = document.getElementById('email-alert');
  const deptAlert = document.getElementById('dept-alert');
  const bodyAlert = document.getElementById('body-alert');
  const resultDetail = document.getElementById('detail');

  const inputValueClear = () => {
    form.name.value = '';
    form.name.setAttribute('class', '');
    form.email.value = DOMAIN;
    form.email.setAttribute('class', '');
    form.dept.value = '';
    form.dept.setAttribute('class', '');
    form.body.value = '';
    form.body.setAttribute('class', '');
    result.innerHTML = '';
  };

  // When the user clicks on <span> (x), close the modal
  span.onclick = () => {
    if (result.innerHTML !== LOADING) {
      modal.style.display = 'none';
      if (result.innerHTML === RESULT_OK) inputValueClear();
    }
  };

  // When the user clicks anywhere outside of the modal, close it
  window.onclick = event => {
    if (event.target === modal) {
      if (result.innerHTML !== LOADING) {
        modal.style.display = 'none';
        if (result.innerHTML === RESULT_OK) inputValueClear();
      }
    }
  };

  sendBtn.addEventListener('click', async event => {
    event.preventDefault();
    const name = form.name.value.trim();
    form.name.value = name;
    const email = form.email.value.trim();
    form.email.value = email;
    const dept = form.dept.value.trim();
    form.dept.value = dept;
    const body = form.body.value.trim();
    form.body.value = body;

    // validation check
    if (validation(name, email, dept, body)) return;

    result.innerHTML = LOADING;
    modalContent.setAttribute('class', 'request-loading');
    modal.style.display = 'block';
    const jsonData = JSON.stringify({ name, email, dept, body });

    try {
      const res = await fetch(URL, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        body: jsonData,
        headers: {
          'Content-Type': 'application/json; charset=utf-8'
        }
      });
      console.log('Response!!', res.status);
      modalContent.setAttribute('class', 'request-success');
      result.innerHTML = RESULT_OK;
      resultDetail.innerHTML = RESULT_OK_DETAIL;
    } catch (error) {
      console.log(error);
      modalContent.setAttribute('class', 'request-fail');
      result.innerHTML = RESULT_NG;
      resultDetail.innerHTML = RESULT_NG_DETAIL;
    }
  });

  const validation = (name, email, dept, body) => {
    let validationResult = false;
    if (!name.length) {
      form.name.setAttribute('class', 'alert-red');
      nameAlert.hidden = false;
      validationResult = true;
    } else {
      form.name.setAttribute('class', 'alert-green');
      nameAlert.hidden = true;
    }
    if (!email.length || !/^[^@]+@sample.com$/.test(email)) {
      form.email.setAttribute('class', 'alert-red');
      emailAlert.hidden = false;
      validationResult = true;
    } else {
      form.email.setAttribute('class', 'alert-green');
      emailAlert.hidden = true;
    }
    if (!dept.length) {
      form.dept.setAttribute('class', 'alert-red');
      deptAlert.hidden = false;
      validationResult = true;
    } else {
      form.dept.setAttribute('class', 'alert-green');
      deptAlert.hidden = true;
    }
    if (!body.length) {
      form.body.setAttribute('class', 'alert-red');
      bodyAlert.hidden = false;
      validationResult = true;
    } else {
      form.body.setAttribute('class', 'alert-green');
      bodyAlert.hidden = true;
    }
    return validationResult;
  };

  form.name.addEventListener('input', event => {
    const name = event.target.value.trim();
    if (!name) {
      event.target.setAttribute('class', 'alert-red');
      nameAlert.hidden = false;
    } else {
      event.target.setAttribute('class', 'alert-green');
      nameAlert.hidden = true;
    }
  });

  form.email.addEventListener('input', event => {
    const email = event.target.value.trim();
    event.target.value = email;
    if (!email || !/^[^@]+@sample.com$/.test(email)) {
      event.target.setAttribute('class', 'alert-red');
      emailAlert.hidden = false;
    } else {
      event.target.setAttribute('class', 'alert-green');
      emailAlert.hidden = true;
    }
  });

  form.dept.addEventListener('input', event => {
    const dept = event.target.value.trim();
    event.target.value = dept;
    if (!dept) {
      event.target.setAttribute('class', 'alert-red');
      deptAlert.hidden = false;
    } else {
      event.target.setAttribute('class', 'alert-green');
      deptAlert.hidden = true;
    }
  });

  form.body.addEventListener('input', event => {
    const body = event.target.value.trim();
    if (!body) {
      event.target.setAttribute('class', 'alert-red');
      bodyAlert.hidden = false;
    } else {
      event.target.setAttribute('class', 'alert-green');
      bodyAlert.hidden = true;
    }
  });
})();

AWS SES(Simple Email Service)を設定

※ドメインはRoute53で取得済みの前提
※併せてACM(AWS Certificate Manager)で証明書を取得済み
※SESは送信のみの設定です。

  1. AWSへログイン
  2. SESのコンソールへ移動
  3. リージョンはバージニア北部を選択
  4. 左のナビゲーションからDomainsを選択
    image.png
  5. image.png をクリック
  6. ↓のように入力。自分のドメインとDKIM設定をチェックして、image.pngをクリックimage.png
  7. 次のモーダルではCNAMEやTXTが表示され、登録しろと指示が出る。Route53を利用している場合は、このモーダル上でDNSの登録がすべて完了する。
  8. こんな感じになればOK!(※現時点ではサンドボックス上での制限された利用が可能)
    image.png
  9. 左のナビゲーションでEmail Addressesを選択
    image.png
  10. Veryfy a New Email Addressでサンドボックス上で利用できるメールアドレスを登録する。
  11. 登録したメールアドレスをSend a Test Emailで登録したドメインからメールが送られるかテストして正常な動作を確認

最後に起動するLambdaを作成

  1. Lambdaのコンソールページへ移動
  2. image.png をクリック
  3. image.png を選択
  4. image.png 適当な関数名を入力
  5. ランタイムはNode.js 12.xを選択
  6. そのほかはデフォルトのままでOK
  7. image.png をクリック
  8. 環境変数へ配信元のアドレスを設定
    image.png
  9. 実行ロールにはSESの権限を許可
    image.png
  10. 関数コードへ↓のコードを実装
index.js
'use strict'
const SES = require("aws-sdk/clients/ses");
const ses = new SES({ region: "us-east-1" }); // 米国東部(バージニア北部)
const FROM = process.env.FROM; // 環境変数から取得

exports.handler = async (event) => {
    console.log(event);
    const TO = [event.email];
    const params = {
        Destination: {
            ToAddresses: TO
        },
        Message: {
            Body: {
                Text: {
                    Data: [
                        event.dept + ' ' + event.name + '',
                        ' ',
                        'Hoge Hoge Companyです。',
                        'お問い合わせしていただきありがとうございます。',
                        '下記の内容で承りました。',
                        ' ',
                        '[お問い合わせ内容]' + "\n" + event.body,
                    ].join("\n"),
                    Charset: "utf-8"
                }
            },
            Subject: {
                Data: '受付完了:Webからの問い合わせ',
                Charset: "utf-8"
            }
        },
        // From
        Source: FROM
    };

    const result = {statusCode: 200};
    try {
        const response = await ses.sendEmail(params).promise();
        console.log('Response: ', response);
        result.body = 'OK!!!!!';
    } catch (error) {
        console.log('Error: ', error);
        result.statusCode = error.code;
        result.body = error.message;
    }
    return result;
};

process.envでは環境変数で設定したキーと値が利用可能(暗号化も可能)

最後に起動するLambdaのテスト

  1. image.png テストイベントの選択をクリック
  2. ↓のようにテストを作成(※emailキーにはSESで登録したアドレスを記載すること)
    image.png
  3. image.png をクリックしてテスト実行
  4. 成功となればOK。失敗ならログを確認。
    image.png
  5. テストでemailキーに指定したアドレスにメールが配信されていればOK

最初に起動するLambdaを作成

  1. Lambdaのコンソールページへ移動
  2. image.png をクリック
  3. image.png を選択
  4. image.png 適当な関数名を入力
  5. ランタイムはNode.js 12.xを選択
  6. そのほかはデフォルトのままでOK
  7. image.png をクリック
  8. 環境変数へ配信元のアドレスと受付先のアドレスを入力
    image.png
  9. 実行ロールはSESとLambdaの権限を追加
    image.png
  10. 関数コードへ↓のコードを実装
index.js
'use strict'
const SES = require("aws-sdk/clients/ses");
const ses = new SES({ region: "us-east-1" }); // 米国東部(バージニア北部)
const TO = [process.env.TO]; // 環境変数からの値を取得
const FROM = process.env.FROM;

// 次のLambdaを起動するための設定
const Lambda = require("aws-sdk/clients/lambda");
const lambda = new Lambda({ region: "ap-northeast-1" });

exports.handler = async (event) => {
    const name = event.form.name;
    const email = event.form.email;
    const dept = event.form.dept;
    const body = event.form.body;
    const sesParams = {
        Destination: {
            ToAddresses: TO
        },
        Message: {
            Body: {
                Text: {
                    Data: [
                        '[名前] : ' + name,
                        '[メールアドレス] : ' + email,
                        '[所属部署] : ' + dept,
                        '[お問い合わせ] : ' + "\n" + body,
                    ].join("\n"),
                    Charset: "utf-8"
                }
            },
            Subject: {
                Data: 'Webからの問い合わせ',
                Charset: "utf-8"
            }
        },
        // From
        Source: FROM
    };

    // 次のLambdaに送るデータ
    const payload = { name, email, dept, body };
    console.log('payload: ', payload);
    const lambdaParams = {
        FunctionName: "inpuirySendMailForm_2nd", // 最後に起動するLambdaの名称
        InvocationType: "Event",
        Payload: JSON.stringify(payload)
    };

    const result = {statusCode: 200};
    try {
        const response = await ses.sendEmail(sesParams).promise();
        console.log('Response: ', response);
        const callLambda = await lambda.invoke(lambdaParams).promise();
        console.log("Lambda Response: ", callLambda);
        result.body = 'OK!!!!!';
    } catch (error) {
        console.log('Error: ', error);
        result.statusCode = error.code;
        result.body = error.message;
    }
    return result;

};

最初に起動するLambdaのテスト(次のLambdaも起動する)

  1. image.png テストイベントの選択をクリック
  2. ↓のようにテストを作成
    image.png
  3. image.png をクリックしてテスト実行
  4. 成功となればOK。失敗ならログを確認。
    image.png
  5. テストでemailキーに指定したアドレスに受付完了メールが配信され、環境変数でTOに指定した受付先アドレスへ問い合わせ内容が配信されていればOK

APIGatewayの設定

  1. image.pngをクリック
  2. REST API構築を選択
    image.png
  3. API名説明を入力してAPIの作成をクリック(他はデフォルト)
    image.png
  4. アクション⇒リソースの作成を選択⇒リソース名を入力(リソースパスは自動入力)⇒CORSを有効化⇒リソースの作成をクリック
  5. アクション⇒メソッドの作成⇒POSTを選択⇒セットアップで最初に起動するLambda関数名を入力⇒保存をクリック
  6. 統合リクエストをクリック⇒マッピングテンプレートを追加⇒Content-Typeはapplication/json⇒テンプレートには↓を入力⇒保存をクリック
{
    "form": {
        "name":  "$util.escapeJavaScript($input.path('$.name'))",
        "email": "$util.escapeJavaScript($input.path('$.email'))",
        "dept":  "$util.escapeJavaScript($input.path('$.dept'))",
        "body":  "$util.escapeJavaScript($input.path('$.body'))"
    }
}

APIGatewayのテスト

  1. テストを実行する
    image.png
  2. Lambdaが起動してメールが配信されればOK

APIGatewayのステージを作成

今回はv1というステージを作成

APIGatewayのデプロイ

リソース⇒アクション⇒APIのデプロイを選択⇒v1ステージを選択して⇒デプロイをクリック

発行されたURLをjavascriptのURL変数へ割り当て

全体の動作確認

問い合わせフォームへSESで登録したアドレスと必要事項を入力し、送信ボタンをクリックして動作を確認

実用化に向けて

  • LambdaのSDK呼び出しは動作確認ができているバージョンが呼び出されるようにする必要あり。
  • SESの上限緩和申請が必要。
  • APIGatewayでリソースポリシーを指定して不要なアクセスを防ぐ

最後に

かなり大雑把に書きました。
小規模利用なら十分かと思います。
役に立つかな?
計画性なく作ってしまったのでここからブラッシュアップ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超初心者がwebpackerについて調べてみたぞ

Ruby on Rails を使って開発を始めた今日この頃。
サーバーサイドはそれとなく出来てきたからそろそろフロントも固めて行こうかしら。なんて思っていた僕はBootstrapをRailsで使おうと考えた。Bootstrapを使うのはいたって簡単。htmlのhead内に以下のリンクをぶち込めばいいだけ

application.html.erb
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

なんて便利だこと。
しかし、Bootstrapを使うには他にも方法はある。それは以下のリンクにある通りだ。
https://qiita.com/rhistoba/items/f724dae231d7e28bf477
つまり、railsにBootstrapをインストールしてしまう方法である。
基本的には、リンクの記事通りに手順を踏めばインストールできるのであるが、超初心者の僕はいくつかのワカラナイ点があったので自分用のメモとして残すことにした。

前提

僕のスペック

  • プログラミング学習を始めて1ヶ月
  • HTML/CSS/Javascript/Ruby/Railsをprogateで一応学習済
  • Ruby on rails でポートフォリオを作成中

開発環境

  • 端末 : LENOVO ideapad 530S-14ARR
  • OS : Windows 10 Home ver.1809
  • シェル : PowerShell 5.1.17763.771
  • Ruby : 2.6.4
  • rails : 5.2.4.1

そもそもwebpackerってなんだ?

webpackerとはwebpackをRubyで使えるようにしたものらしい。
僕「webpackかぁ~…聞いたことあるよ。…でもよく知らない。」

webpackとは?

調べたところ、webpack というのは

Webpackとは、CSS、JavaScript、画像などを1つのファイルとしてまとめるためのモジュールバンドラーで、node.jsのモジュールの1つです。

とのこと。(引用元:https://www.sejuku.net/blog/68146)
僕「モジュールバンドラーってなんだよぉ(´;ω;`)」
僕「node.jsもよく分かんねーよぉ(´;ω;`)」
調べても分からないが続く。まさに分からないリレー状態。

モジュールバンドラーとは?

次にモジュールバンドラーについて知らべてみた。
モジュールバンドラーとはその名の通り、モジュール(部品)をまとめたものをいうらしい。ここでモジュールとはあるプログラムと考えるのが良さげ。

例えば、現在時刻を表示するプログラムを作るとしよう。ここで、現在時刻を取得するコードと、それを表示するコードと分けて作ったとする。これらのコードを合体させたいのだが、その方法として、表示するためのコードに現在時刻を取得するコードをインポートすることにしよう。この時、インポートされる側のコードをモジュールと呼ぶ

このような便利なコード集をモジュールバンドラーというみたい。
(参考:https://note.com/billion_dollars/n/n596fecfdeb2e)

node.jsとは?

node.jsとはサーバーサイドJavascriptである。
Javascriptは本来、ブラウザで動き見た目を作る(フロントで活躍する)言語なのだが、「この言語でサーバーサイドも作れたら嬉しくね?」という発想から作られたJavaScript 環境なんだとか。

僕「なるほどぉ。すごいじゃんnode.js」

(参考:https://eng-entrance.com/what-is-nodejs#Nodejs-2)

改めてwebpackって何ぞや?

ここまで調べたことをまとめて、もう一度考えるとwebpackとは、

CSS、JavaScript、画像などの部品を上手にまとめて1つにするnode.js(Javascript環境の1つ)のモジュールだ!

ということですね。要するにまとめ上手なお兄さんみたいな(雑)

とはいえ、なんでそんなにまとめたがるのか?

なんとなくwebpackについて分かったけど、まとめることにどんなメリットがあるのかしら?調べてみると通信との関係があるみたいだ。
僕たちがwebサイトを閲覧する時は、自分のPCからサーバーにリクエストを送り、そのレスポンスとしてあるwebページ(htmlファイルとか)を返してくれる。
しかし、そのhtmlが様々なコード(モジュール)や画像、css、javascriptなどを引用してきている時には、それらも同時に送ってやらないと不完全なwebページしか閲覧できない。だからそういう関係するファイルも一緒に送ってやるのだが、これらがバラバラだとサーバーがPCに送るのに時間が掛かってしまうみたい。
ここでそれらのファイルが1つにまとまっていることで素早く通信できるようだ。

まとめ

webpackerのことを調べて、本来の目的であるBootstrapのインストール忘れてた(/ω\)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む