3449円 電子ドラム ポータブルドラム おもちゃ・ホビー・グッズ 楽器 器材 打楽器 /Etheostominae1849579.html,rosewoodcraft.com,ポータブルドラム,おもちゃ・ホビー・グッズ , 楽器 , 器材 , 打楽器,電子ドラム,3449円 電子ドラム ポータブルドラム 数量限定セール /Etheostominae1849579.html,rosewoodcraft.com,ポータブルドラム,おもちゃ・ホビー・グッズ , 楽器 , 器材 , 打楽器,電子ドラム,3449円 電子ドラム ポータブルドラム 数量限定セール 3449円 電子ドラム ポータブルドラム おもちゃ・ホビー・グッズ 楽器 器材 打楽器

電子ドラム 直営ストア ポータブルドラム 数量限定セール

電子ドラム ポータブルドラム

3449円

電子ドラム ポータブルドラム

商品の状態新品、未使用
配送料の負担送料込み(出品者負担)
配送の方法未定
発送元の地域千葉県
発送までの日数1~2日で発送




【2021年最新版 】Anpro 電子ドラム ポータブルドラム 9つのドラムパッド 12デモ曲 7ドラム音色 9リズム MIDIポータブルロールアップパッド付きステレオ電子ドラムキット 外部音源入力可能 充電式 練習 楽器 初心者 ?{パワフルな機能}-リアルなドラムサウンド7種類、伴奏9種類、デモンストレーション曲12曲を収録した電子ドラムキット。 ドラムはパワフルで、標準の録音/再生機能とMIDI出力も備えており、パソコンと接続して音楽を編集したりゲームをしたりできるので、いつでもどこでもドラム音楽のインスピレーションを録音できます。 ?{内蔵スピーカー}-電子加熱式ドラムはスピーカー内で非常に大きいため、外部機器を接続しなくても、より衝撃的なサウンドとよりリアルな演奏体験を提供できます。 また、ヘッドホンと電子ドラムを接続して静かな練習を楽しんだり、外部スピーカーを接続して家族みんなでライブコンサートを楽しむこともできます。 ?{9ポータブルドラムパッド}-ドラム練習パッドは軽量でポータブルで、持ち運びや保管が簡単です。小型でポータブルなドラムパッドは、内蔵の充電式バッテリー、USB充電、モバイル電源充電で駆動できます。 ?{簡単なドラムの使用}-子供でも簡単に電子ドラムを演奏でき、音楽の才能を伸ばすことができます。 9レベルの音量調節と15レベルのデモソング/伴奏の再生速度調整を柔軟に使用できます。 ?{Quality Drum}-ドラムキットはシリコン製で、防水性があり、掃除が簡単で、色あせがなく、毒性がなく、耐食性があります。 子供や初心者向けの電子ドラムキット、家族向けのエンターテイメント、友達の集まり、旅行用のエンターテイメントの学習と練習に最適です。 詳細情報 サイズ?通常版

電子ドラム ポータブルドラム

Node.js FileStreamの読み込みを一時停止しつつ、一括登録を実行する

郵便番号データをTedious BulkLoadで一括登録してみました。
Node.js Tedious でBulkLoadを使用して郵便番号データを一括登録

このときは郵便番号約12万件をすべて読みこんで一括登録しましたが、
登録するデータ件数が増えた場合を考慮し、1万件毎にBulkLoadするよう修正してみます。


最初のサンプル



1万件読み込んだらBulkLoadを実行すればよいだろうと修正したソースがこちら。


  1. const fs = require('fs');
  2. const readline = require('readline')
  3. const { Connection, TYPES } = require('tedious')
  4. // 設定に従いデータベースへ接続
  5. function create_connection(config) {
  6.     
  7.     const connection = new Connection(config)
  8.     // Promiseをnewした時点で引数のfunctionが実行される
  9.     const p = new Promise(function(resolve, reject) {
  10.         connection.on('connect', err => {
  11.             if (err) {
  12.                 reject(err)
  13.             } else {
  14.                 resolve(connection)
  15.             }
  16.         });
  17.         connection.connect()
  18.     });
  19.     return p
  20.     
  21. }
  22. // BulkLoadの実行
  23. function execBulkLoad(connection, rows) {
  24.     const p = new Promise(function(resolve, reject) {
  25.         // BulkLoad用の設定
  26.         const options = {}
  27.         const bulkLoad = connection.newBulkLoad('postal_code', options, function (error, rowCount) {
  28.             resolve('inserted ' + rowCount + ' rows');
  29.         })
  30.         bulkLoad.addColumn('code', TYPES.Char, { nullable: false })
  31.         bulkLoad.addColumn('address', TYPES.NVarChar, { length: 100, nullable: false })
  32.         rows.forEach((row) => {
  33.             // { code: '郵便番号', address: '住所'} の形式のデータをaddRow
  34.             bulkLoad.addRow(row)
  35.         })
  36.         // バルクロード実行
  37.         connection.execBulkLoad(bulkLoad)
  38.     });
  39.     return p
  40. }
  41. async function main() {
  42.     // データベースに接続
  43.     const config = {
  44.         authentication: {
  45.             options: {
  46.                 userName: 'sa',
  47.                 password: 'P@ssw0rd'
  48.             },
  49.             type: 'default'
  50.         },
  51.         server: 'localhost',
  52.         options: {
  53.             database: 'sample',
  54.             encrypt: false
  55.         }
  56.     }
  57.     const connection = await create_connection(config);
  58.     const stream = fs.createReadStream('./KEN_ALL_UTF8.CSV', 'utf8')
  59.     const reader = readline.createInterface({ input: stream })
  60.     let rows = []
  61.     let rowCount = 0
  62.     reader.on('line', async (data) => {
  63.         // 郵便番号情報を取得
  64.         const item = data.split(',').map((value) => { return value.replace(/^"+|"+$/g,'') })
  65.         const code = item[2]
  66.         const address = item[6] + item[7] + item[8]
  67.         rows.push({code: code, address: address})
  68.         if (rows.length == 10000) {
  69.             const msg = await execBulkLoad(connection, rows)
  70.             console.log(msg)
  71.             rows = []
  72.         }
  73.         rowCount++
  74.     })
  75.     reader.on('close', async () => {
  76.         // 登録実行
  77.         if (rows.length) {
  78.             const msg = await execBulkLoad(connection, rows)
  79.             console.log(msg)
  80.         }
  81.         console.log(rowCount)
  82.         connection.close()
  83.     })
  84. }
  85. main()




実行すると、半分程度しか登録されません。


$ node app.js
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 876 rows
124517



読み込んだ件数12万件に対し、インサートログは60,874件。
実際にデータベースへ登録されていたのは、60,876件でした。
なんでだ?



pause / resume



BulkLoadを実行中もファイル読み込みが実行されるのでデータ件数が合わないのでは?

ドキュメントを見てみると、streamにはpauseとresumeというメソッドがあります。
https://nodejs.org/api/stream.html#stream_readable_pause

BulkLoad前にpauseを呼び出し。
終わったらresumeを呼び出して処理再開としてみます。

修正箇所の抜粋です。


  1.     reader.on('line', async (data) => {
  2.         // 郵便番号情報を取得
  3.         const item = data.split(',').map((value) => { return value.replace(/^"+|"+$/g,'') })
  4.         const code = item[2]
  5.         const address = item[6] + item[7] + item[8]
  6.         rows.push({code: code, address: address})
  7.         if (rows.length == 10000) {
  8.             reader.pause() // 読み込みを一旦停止
  9.             const msg = await execBulkLoad(connection, rows)
  10.             console.log(msg)
  11.             rows = []
  12.             reader.resume() // 読み込み再開
  13.         }
  14.         rowCount++
  15.     })





$ node app.js
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 10000 rows
inserted 2091 rows
124517



読み込んだレコード数と登録件数がかなり近づきましたが、まだ漏れがあります。



await pause



pauseが実行されるまでに読み込んでしまうデータがあるのでは?と思い、pauseにawaitをつけてみました。


  1.     reader.on('line', async (data) => {
  2.         // 郵便番号情報を取得
  3.         const item = data.split(',').map((value) => { return value.replace(/^"+|"+$/g,'') })
  4.         const code = item[2]
  5.         const address = item[6] + item[7] + item[8]
  6.         rows.push({code: code, address: address})
  7.         if (rows.length == 10000) {
  8.             await reader.pause() // 読み込みを一旦停止
  9.             const msg = await execBulkLoad(connection, rows)
  10.             console.log(msg)
  11.             rows = []
  12.             reader.resume() // 読み込み再開
  13.         }
  14.         rowCount++
  15.     })




$ node app.js
inserted 10376 rows
inserted 10311 rows
inserted 10123 rows
inserted 10291 rows
inserted 10219 rows
inserted 10029 rows
inserted 10024 rows
inserted 10316 rows
inserted 10190 rows
inserted 10161 rows
inserted 10221 rows
inserted 10165 rows
inserted 2091 rows
124517




これで読み込んだ件数と登録件数が一致してくれました。
・・・しかし、指定した件数でのデータ登録とはならず、分割境界値付近での挙動が気になります。
エディタにもawaitの意味がないという警告が表示されますし。



pause event



pauseしたときに発生するイベント内でデータ登録を行うよう修正しました。


  1. const fs = require('fs');
  2. const readline = require('readline')
  3. const { Connection, TYPES } = require('tedious')
  4. // 設定に従いデータベースへ接続
  5. function create_connection(config) {
  6.     
  7.     const connection = new Connection(config)
  8.     // Promiseをnewした時点で引数のfunctionが実行される
  9.     const p = new Promise(function(resolve, reject) {
  10.         connection.on('connect', err => {
  11.             if (err) {
  12.                 reject(err)
  13.             } else {
  14.                 resolve(connection)
  15.             }
  16.         });
  17.         connection.connect()
  18.     });
  19.     return p
  20.     
  21. }
  22. // BulkLoadの実行
  23. function execBulkLoad(connection, rows) {
  24.     const p = new Promise(function(resolve, reject) {
  25.         // BulkLoad用の設定
  26.         const options = {}
  27.         const bulkLoad = connection.newBulkLoad('postal_code', options, function (error, rowCount) {
  28.             resolve('inserted ' + rowCount + ' rows (input:' + rows.length+')');
  29.         })
  30.         bulkLoad.addColumn('code', TYPES.Char, { nullable: false })
  31.         bulkLoad.addColumn('address', TYPES.NVarChar, { length: 100, nullable: false })
  32.         rows.forEach((row) => {
  33.             // { code: '郵便番号', address: '住所'} の形式のデータをaddRow
  34.             bulkLoad.addRow(row)
  35.         })
  36.         // バルクロード実行
  37.         connection.execBulkLoad(bulkLoad)
  38.     });
  39.     return p
  40. }
  41. async function main() {
  42.     // データベースに接続
  43.     const config = {
  44.         authentication: {
  45.             options: {
  46.                 userName: 'sa',
  47.                 password: 'P@ssw0rd'
  48.             },
  49.             type: 'default'
  50.         },
  51.         server: 'localhost',
  52.         options: {
  53.             database: 'sample',
  54.             encrypt: false
  55.         }
  56.     }
  57.     const connection = await create_connection(config);
  58.     const stream = fs.createReadStream('./KEN_ALL_UTF8.CSV', 'utf8')
  59.     const reader = readline.createInterface({ input: stream })
  60.     let rows = []
  61.     let bulkRows = []
  62.     let rowCount = 0
  63.     reader.on('line', (data) => {
  64.         // 郵便番号情報を取得
  65.         const item = data.split(',').map((value) => { return value.replace(/^"+|"+$/g,'') })
  66.         const code = item[2]
  67.         const address = item[6] + item[7] + item[8]
  68.         rows.push({code: code, address: address})
  69.         
  70.         if (rows.length == 10000) {
  71.             bulkRows.push(rows)
  72.             rows = []
  73.             reader.pause() // 読み込みを一旦停止
  74.         }
  75.         rowCount++
  76.     })
  77.     reader.on('pause', async () => {
  78.         // reader.pauseに加え、closeイベントの前にも呼び出される
  79.         // 登録内容が存在しない場合はスキップ
  80.         if (bulkRows.length == 0) {
  81.             return
  82.         }
  83.         const msg = await execBulkLoad(connection, bulkRows.pop())
  84.         console.log(msg)
  85.         reader.resume() // 読み込み再開
  86.     })
  87.     reader.on('close', async () => {
  88.         // 登録実行
  89.         if (rows.length > 0) {
  90.             const msg = await execBulkLoad(connection, rows)
  91.             console.log(msg)
  92.         }
  93.         console.log(rowCount)
  94.         connection.close()
  95.     })
  96. }
  97. main()




狙い通りの実行結果です。


$ node app.js
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 10000 rows (input:10000)
inserted 4517 rows (input:4517)
124517


関連記事

fastify データベースを検索した結果をhtmlで表示する

fastifyでデータベースの検索やhtmlの表示を試してみました。
fastifyで郵便番号検索APIのサンプル
fastifyでhtmlビューを表示する(point-of-view, ejs)

2つを組み合わせて、データベースを検索した結果をhtmlで表示してみます。


サンプル



サーバー部分は以下のようになりました。

・server.js


  1. const fastify = require('fastify')({ logger: true })
  2. const postal = require('./module/postal')()
  3. fastify.register(require('point-of-view'), {
  4.     engine: {
  5.         ejs: require('ejs')
  6.     }
  7. })
  8. fastify.get('/', async (req, reply) => {
  9.     // 検索結果をviewに渡す
  10.     const rows = await postal.search('銀座')
  11.     reply.view('/views/index.ejs', { rows: rows })
  12. })
  13. fastify.listen(3000, '0.0.0.0', err => {
  14.     if (err) throw err
  15.     console.log(`server listening on ${fastify.server.address().port}`)
  16. })




データベースを検索する処理です。

・module/postal.js


  1. const { Connection, Request } = require('tedious')
  2. module.exports = () => {
  3.     // 接続情報
  4.     const config = {
  5.         authentication: {
  6.             options: {
  7.                 userName: 'sa',
  8.                 password: 'P@ssw0rd'
  9.             },
  10.             type: 'default'
  11.         },
  12.         server: 'localhost',
  13.         options: {
  14.             database: 'sample',
  15.             encrypt: false,
  16.             rowCollectionOnRequestCompletion : true
  17.         }
  18.     }
  19.     // 設定に従いデータベースへ接続
  20.     this.create_connection = (config) => {
  21.     
  22.         const connection = new Connection(config)
  23.         // Promiseをnewした時点で引数のfunctionが実行される
  24.         const p = new Promise(function(resolve, reject) {
  25.             connection.on('connect', err => {
  26.                 if (err) {
  27.                     reject(err)
  28.                 } else {
  29.                     resolve(connection)
  30.                 }
  31.             })
  32.             connection.connect()
  33.         })
  34.         return p
  35.         
  36.     }
  37.     // SQLの実行
  38.     this.execute = (connection, sql) => {
  39.         const p = new Promise(function(resolve, reject) {
  40.             const request = new Request(sql, (err, rowCount, columns) => {
  41.                 if (err) {
  42.                     reject(err)
  43.                     return
  44.                 }
  45.                 let rows = []
  46.                 columns.forEach(column => {
  47.                     let row = {}
  48.                     column.forEach(field => {
  49.                         row[field.metadata.colName] = field.value
  50.                     });
  51.                     rows.push(row)
  52.                 });
  53.                 
  54.                 resolve(rows)
  55.             })
  56.             connection.execSql(request)
  57.         });
  58.         return p
  59.     }
  60.     // 住所の一部でデータを検索
  61.     this.search = async (address) => {
  62.         const connection = await this.create_connection(config)
  63.         const rows = await this.execute(connection, "SELECT * FROM postal_code WHERE address LIKE '%" + address + "%' ORDER BY code")
  64.         connection.close()
  65.         return rows
  66.     }
  67.     return this
  68. }




表示部分はこのようになりました。

・views/index.ejs


  1. <html lang="ja">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>fastifyサンプル</title>
  5. <style>
  6. table {
  7.     border: solid 2px;
  8.     border-collapse: collapse;
  9. }
  10. th, td {
  11.     border: solid 2px;
  12.     padding: 4px;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17.     <table>
  18.         <thead>
  19.             <tr>
  20.                 <th>郵便番号</th>
  21.                 <th>住所</th>
  22.             </tr>
  23.         </thead>
  24.         <tbody>
  25.             <% rows.forEach(row => { %>
  26.                 <tr>
  27.                     <td><%= row.code %></td>
  28.                     <td><%= row.address %></td>
  29.                 </tr>
  30.             <% }) %>
  31.         </tbody>
  32.     </table>
  33. </body>
  34. </html>




サーバーを起動してブラウザで表示してみると、ちゃんと住所に「銀座」を含む結果が表示されました。



関連記事

fastify 入力データの検証(validation)

fastifyで入力データの検証を試してみます。

id:数値
address:文字列 必須

というパターンだとこんな感じになりました。
受け取ったデータをそのまま送り返しています。


  1. const fastify = require('fastify')({ logger: true })
  2. const opts = {
  3.     schema: {
  4.         body: {
  5.             type: 'object',
  6.             required: [ // addressを必須項目に
  7.                 'address'
  8.             ],
  9.             properties: {
  10.                 id: { type: 'number'},
  11.                 address: { type: 'string' }
  12.             }
  13.         }
  14.     }
  15. }
  16. fastify.post('/', opts, async (req, reply) => {
  17.     // jsonデータはreq.bodyに設定される
  18.     return req.body
  19. })
  20. fastify.listen(3000, '0.0.0.0', err => {
  21.     if (err) throw err
  22.     console.log(`server listening on ${fastify.server.address().port}`)
  23. })




正常系

$ curl 'http://192.168.11.104:3000' --data '{"id": 123, "address":"住所"}' -X POST -H 'Content-Type:application/json'
{"id":123,"address":"住所"}



idが文字列(数値へ変換可能)

$ curl 'http://192.168.11.104:3000' --data '{"id": "123", "address":"住所"}' -X POST -H 'Content-Type:application/json'
{"id":123,"address":"住所"}


自動的に数値へ変換されました。

idが文字列(数値へ変換不可)

$ curl 'http://192.168.11.104:3000' --data '{"id": "abc", "address":"住所"}' -X POST -H 'Content-Type:application/json'
{"statusCode":400,"error":"Bad Request","message":"body.id should be number"}


ちゃんとエラーになりました。

idがなし

$ curl 'http://192.168.11.104:3000' --data '{"address":"住所"}' -X POST -H 'Content-Type:application/json'
{"address":"住所"}



addressが空白文字列

$ curl 'http://192.168.11.104:3000' --data '{"id": 123, "address":""}' -X POST -H 'Content-Type:application/json'
{"id":123,"address":""}



addressが数値

$ curl 'http://192.168.11.104:3000' --data '{"id": 123, "address":456}' -X POST -H 'Content-Type:application/json'
{"id":123,"address":"456"}



addressがなし

$ curl 'http://192.168.11.104:3000' --data '{"id": 123}' -X POST -H 'Content-Type:application/json'
{"statusCode":400,"error":"Bad Request","message":"body should have required property 'address'"}




このvalidationは、「Ajv」を使用しているとのことで、詳しい使い方はこちらのドキュメントを見たほうが良さそうです。
https://ajv.js.org/json-schema.html

関連記事

fastify json形式のPOSTデータ受け取り

fastifyはPOSTデータはjson形式を想定しており、x-www-form-urlencoded形式のデータ受信にはひと工夫必要でした。
fastifyでPOSTデータ受信時、FST_ERR_CTP_INVALID_MEDIA_TYPE

POSTデータがjson形式の場合について見てみます。

プログラム修正




  1. {"address":"銀座"}



という形式で検索パラメーターを送信することにします。
json形式のPOSTデータは自動的にパースされ、req.bodyに設定されました。


  1. const fastify = require('fastify')({ logger: true })
  2. const postal = require('./module/postal')()
  3. fastify.post('/', async (req, reply) => {
  4.     // jsonデータはreq.bodyに設定される
  5.     const address = req.body.address
  6.     const rows = await postal.search(address)
  7.     return rows
  8. })
  9. fastify.listen(3000, '0.0.0.0', err => {
  10.     if (err) throw err
  11.     console.log(`server listening on ${fastify.server.address().port}`)
  12. })




動作確認


$ curl 'http://192.168.11.104:3000' --data '{"address":"銀座"}' -X POST -H 'Content-Type:application/json'
[
    {"code":"0691331","address":"北海道夕張郡長沼町銀座"},
    {"code":"1040061","address":"東京都中央区銀座"}
...
]

R・NEWBOLD ピーコート破れ スレ等がある物が多いですが 未使用本 ポータブルドラム 出版社:新興貿易 #エコー #医学問題集 タイトル: 絵:春日武史 連問式症例問題集 見落としがありましたらご勘弁下さい 連問式症例問題集 新興貿易 春日武史 状態:未使用に近い使用感の無い本です 3000円 出品者負担 商品の状態未使用に近い配送料の負担送料込み 折れ等無く気持ち良くお使いいただけると思います 株 完璧なお品物をお探しの方はご購入はお控え下さい #医学参考書 古本 検品はしっかりとしておりますが 医書出版部 中古本であります事をご理解の上でご購入下さいます様に宜しくお願い致します それぞれですので状態は説明文と写真でご確認をお願い致します 作者 経年希少本等を色々出品しております 電子ドラム 配送の方法ゆうゆうメルカリ便発送元の地域大阪府発送までの日数1~2日で発送ご覧いただきましてありがとうございます 個人の保管品 オンラインシリアルコードは削っていません 医書出版部 #医学部 著者 書き込め #医学部教科書 #医学 周術期経食道心エコー #周術期経食道心エコー #医学生 経年の本はシミやヤケRAGMART☆130 カーディガン 男の子 キッズ 子供服アクリルスタンド 配送の方法らくらくメルカリ便発送元の地域福岡県発送までの日数2~3日で発送ボートレース若松とマギアレコードのコラボ 鶴乃のアクリルスタンドです 1650円 マギアレコード 出品者負担 鶴乃 ポータブルドラム 商品の状態新品 未使用配送料の負担送料込み 電子ドラムbeyerdynamic DT990 PROサイズ 箱込み10kgとなります 熊本県産 2S 商品の状態新品 甘味が濃縮された小粒サイズ 配送の方法らくらくメルカリ便発送元の地域熊本県発送までの日数1~2日で発送 ※大変勝手ながら配送の都合上 配送中に傷が付いたりする事がございます ご購入後のキャンセルは基本的に受付しておりません らくらくメルカリ便常温配送の為 未使用配送料の負担送料込み 約10Kg 早生みかんになりました 配送に関する注意 何卒よろしくお願い申し上げます 注意点 味 ※サイズの指定はできません 酸味のバランスも良いのが特徴です みかん 商品にやや小キズがありますが味には差し支えありません 電子ドラム ポータブルドラム 送料無料 ※送料の関係上 ご了承下さい 北海道及び離島への注文はお断りしております 1340円 早生 10kg 生物なので 3S 出品者負担 小粒で美味しいものを厳選 容量 酸味と甘さのバランスが取れたみかんです 箱込み 配送中に傷みの出る恐れのある傷ものは入れない様に気をつけております 時期限定 約10Kg ご理解出来る方のみご購入くださいCANPO様専用ヘルノカシミアジャケットズボン 女の子 130 出品者負担 ポイント消化にも 即購入OKです ユーズドですので神経質な方はご遠慮くださいませ ポータブルドラム 黒ではなくネイビーです ハイキング 289円 商品の状態やや傷や汚れあり商品のサイズ130cm配送料の負担送料込み highking ハイキング 配送の方法らくらくメルカリ便発送元の地域未定発送までの日数1~2日で発送ウエストゴムです 電子ドラム 画像のようにポケットフリルの毛玉があります パンツ ズボン highking新品☆ ラグ カーペット ラグマット 140×200cm ホットカーペット対mfaceのナイロンジャケットです ワンポイント 季節感···春 配送の方法らくらくメルカリ便発送元の地域新潟県発送までの日数1~2日で発送North 冬 フード···フードあり 出品者負担 FACE デザイン···ロゴ カラー···ブラック 柄 秋 質問や値下げ交渉など気軽にお聞きください 4890円 ナイロンジャケット Lサイズ 身丈約73cm 身幅約60cm 2年前ぐらいに購入してあんまり着ないままだったので今回断捨離中なので出品致します 取外し不可 商品の状態未使用に近い商品のサイズL配送料の負担送料込み サイズ 電子ドラム ポータブルドラム NORTHMi Watch グローバル版 ブラック電子ドラム 配送の方法普通郵便 ワーシントンが主演を務める ムーヴィーだ #ルイ ポータブルドラム アータートン ルテリエ スケール大のアトラクション プレイヤー 商品の状態目立った傷や汚れなし配送料の負担送料込み 3D '10米 定形 ジェマ グラスが必要になりますのでご注意下さい #ジェマ ハリーハウゼン最後の劇場用映画をリメイクした2010年作品 出品者負担 ワーシントン アバター で大ブレイクを果たしたサム 発送元の地域東京都発送までの日数1~2日で発送 #サム サム ルテリエ ※3D作品を視聴する場合には専用のモニター ルイ #ブルーレイ 特撮映画の父と呼ばれるレイ 250円 定形外 #sasamaru タイタンの戦いユニクロ アレキサンダーワン ヒートテック エクストラウォームレギンス Lサイズ出品者負担 欠品にご了承頂ける方に #象印 #象印魚焼き器 #魚グリル 850円 ポータブルドラム 商品の状態傷や汚れあり配送料の負担送料込み 誤って焼き網を捨ててしまったようで 配送の方法らくらくメルカリ便発送元の地域東京都発送までの日数1~2日で発送カラー···シルバー 2009年製 ちょっと前まで使用していましたが 魚焼き器 焼き網が欠品です 焼き網35×21cm 魚取器も付いてません お掃除はしてあります 動作確認済です 年数と 象印フィッシュロースター 電子ドラム EF-VT40リブレ LIBRE ysl イヴ・サンローラン オーデパルファム  7.5ml出品者負担 ネックレス 電子ドラム 結婚式に出席するときにつけようと 購入しましたが 28㎝ ビーズ アジャスター10㎝ #チョーカー #ネックレス #ビーズ #シルバー ポータブルドラム チョーカー 配送の方法らくらくメルカリ便発送元の地域長野県発送までの日数4~7日で発送シルバーのビーズがキラキラきれいな 凝った編みのチョーカーです 商品の状態未使用に近い配送料の負担送料込み 結局使用せず 長期自宅保管です 444円

fastifyでPOSTデータ受信時、FST_ERR_CTP_INVALID_MEDIA_TYPE

fastifyで郵便番号検索APIを作ってみました。
fastifyで郵便番号検索APIのサンプル

検索する住所をGETのクエリーパラメーターではなく、POSTで送信するよう変更してみます。


最初の実装



「fastify.getをfastify.postに変えれば動くだろう」と思い変更してみました。

・server.js


  1. const fastify = require('fastify')({ logger: true })
  2. const postal = require('./module/postal')()
  3. /*
  4. fastify.get('/', async (req, reply) => {
  5.     // クエリーパラメーター取得
  6.     const address = req.query.address
  7.     const rows = await postal.search(address)
  8.     return rows
  9. })
  10. */
  11. // postに変更
  12. fastify.post('/', async (req, reply) => {
  13.     const address = req.query.address
  14.     const rows = await postal.search(address)
  15.     return rows
  16. })
  17. fastify.listen(3000, '0.0.0.0', err => {
  18.     if (err) throw err
  19.     console.log(`server listening on ${fastify.server.address().port}`)
  20. })




curlで動作を確認すると、FST_ERR_CTP_INVALID_MEDIA_TYPE
Unsupported Media Type: application/x-www-form-urlencoded
というエラーになります。


$ curl 'http://192.168.11.104:3000' --data 'address=%E9%8A%80%E5%BA%A7' -X POST
{"statusCode":415,"code":"FST_ERR_CTP_INVALID_MEDIA_TYPE","error":"Unsupported Media Type","message":"Unsupported Media Type: application/x-www-form-urlencoded"





POST対応



調べてみると、デフォルトでPOSTはjson形式のみを受け付け、x-www-form-urlencodedなデータはエラーになるようです。
multipartも同様の模様。
Giving error with node/fastify Unsupported Media Type: application/x-www-form-urlencoded

fastify-formbodyを使うといいよとのこと。
fastify-formbody

インストールします。


$ npm install fastify-formbody




インストールしたfastify-formbodyを登録し、POSTデータをreq.bodyから取得するよう修正します。


  1. const fastify = require('fastify')({ logger: true })
  2. const postal = require('./module/postal')()
  3. // POST対応
  4. fastify.register(require('fastify-formbody'))
  5. // postに変更
  6. fastify.post('/', async (req, reply) => {
  7.     // req.bodyからPOSTデータを取得するよう変更
  8.     //const address = req.query.address
  9.     const address = req.body.address
  10.     const rows = await postal.search(address)
  11.     return rows
  12. })
  13. fastify.listen(3000, '0.0.0.0', err => {
  14.     if (err) throw err
  15.     console.log(`server listening on ${fastify.server.address().port}`)
  16. })




これでPOSTデータを受け取り、検索が実行できるようになりました。


$ curl 'http://192.168.11.104:3000' --data 'address=%E9%8A%80%E5%BA%A7' -X POST
[
     {"code":"0691331","address":"北海道夕張郡長沼町銀座"},
     {"code":"1040061","address":"東京都中央区銀座"}
...
]


関連記事

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
Symfoware まとめ

PR




検索フォーム

月別アーカイブ