見出し画像

Next.js × Express で日記アプリ制作 part4

part4ではカスタムサーバーを編集しMongoDBへの投稿の保存、投稿の所得、表示を行っていきます。

part3でははMongoDB Atlasのアカウント作成、カスタムサーバーの作成、daily-appとMongoDB Atlasの接続を行いました。まだ見ていない方はこちらから見ることをお勧めします。

GETとPOSTとは

HTTPリクエストのGETメソッドとPOSTメソッドのことです。

HTTPリクエストとは

クライアントがサーバーに送るリクエスト(要求)のことです。

POSTの設定

初めにpostを設定するためにカスタムサーバーを下記の様に設定していきます。

//ssr-server.js
const express = require('express')
const next = require('next')
   
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

const mongoose = require('mongoose');
const connectOption = {
 useUnifiedTopology: true,
 useNewUrlParser: true
}
mongoose.connect('mongodb+srv://<dbname>:<dbpassword>@cluster0-hapan.mongodb.net/test?retryWrites=true&w=majority', connectOption);

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', () => console.log('DB connection successful'));
const dailySchema = require('./model/dailySchema');
const Daily = mongoose.model('daily', dailySchema, 'daily');
   
app.prepare()
.then(() => {
 const server = express()
 //ここから追加
 server.use(express.json());
 
 server.post('/addDaily/post', async (req, res) => {
   const daily = new Daily({
     title: req.body.title,
     content: req.body.content,
     created: Date.now(),
   });
   const sevedDaily = await daily.save();

   return app.render(req, res, '/addDaily', req.query)
 });
 //ここまで追加
   
 server.get('*', (req, res) => {
   return handle(req, res)
 })
   
 server.listen(3000, (err) => {
   if (err) throw err
   console.log('> Ready on http://localhost:3000')
 })
})
.catch((ex) => {
 console.error(ex.stack)
 process.exit(1)
})

ポイントは以下のコード達です。

server.use(express.json());

この記述によりJsonデータをreq.bodyで操作できる様になります。

server.post('/addDaily/post', async (req, res) => {
   const daily = new Daily({
     title: req.body.title,
     content: req.body.content,
     created: Date.now(),
   });
   const sevedDaily = await daily.save();

   return app.render(req, res, '/addDaily', req.query)
 });

httpメソッドを指定した後にdailyに追加するデータを代入しdaily.saveでデータベースに保存しています。

次にaddDaily.jsを下記の様に編集していきます。

//addDaily.js
import Router from 'next/router' //ここを追加
import { Row, Col, Card, Form, Button} from 'react-bootstrap';
import Header from "../components/Header"

export default class addDaily extends React.Component{
 //ここから追加
 constructor(props) {
   super(props);
   this.state = {
     title: '',
     content: ''
   };

   this.handleChange = this.handleChange.bind(this);
   this.handleSubmit = this.handleSubmit.bind(this);
 }

 handleChange(event) {
   const target = event.target;
   const name = target.name;
   const value = target.value;

   this.setState({
     [name]: value
   });
 }

 handleSubmit(event) {
   fetch(
     '/addDaily/post', {
     method: 'POST',
     body: JSON.stringify({
       title: this.state.title,
       content: this.state.content,
     }),
     headers: {
       'Content-Type': 'application/json; charset=utf-8',
     }
   }
   );
   Router.push({
     pathname: '/index',
   });
   event.preventDefault();
 }
 //ここまで追加


 render(){
   return (
     <div>
       <Header />
       
       <Row className="mt-4">
         <Col xs={12} md={{span: 6, offset: 3}}>
           <Card>
             <Card.Header>lulu</Card.Header>
             <Card.Body>
               //ここから編集
               <Form onSubmit={this.handleSubmit}>
                 <Form.Group>
                   <Form.Label>タイトル</Form.Label>
                   <Form.Control
                     name="title"
                     type="text"
                     placeholder="Please enter a title"
                     value={this.state.title}
                     onChange={this.handleChange}
                   />
                 </Form.Group>
                 <Form.Group>
                   <Form.Label>内容</Form.Label>
                   <Form.Control
                     as='textarea'
                     rows='3'
                     name="content"
                     type="text"
                     placeholder="Please enter a content"
                     value={this.state.content}
                     onChange={this.handleChange}
                   />
                 </Form.Group>
                 <Button variant="primary" type="submit">
                   追加
                 </Button>
               </Form>
               //ここまで編集
             </Card.Body>
           </Card>
         </Col>
       </Row>
     </div>
   )
 }
}

これでpostの設定はできましたので、npm run devでサーバーを立ち上げhttp://localhost:3000/addDailyにアクセスし各項目を記入した後に追加ボタンを押すとデーターベースに保存されます。

スクリーンショット 2020-04-21 10.08.04

スクリーンショット 2020-04-21 10.08.21

GETの設定

次にGETを設定するためにカスタムサーバーを下記の様に設定していきます。

//ssr-server.js
const express = require('express')
const next = require('next')
   
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

const mongoose = require('mongoose');
const connectOption = {
 useUnifiedTopology: true,
 useNewUrlParser: true
}
mongoose.connect('mongodb+srv://<dbname>:<dbpassword>@cluster0-hapan.mongodb.net/test?retryWrites=true&w=majority', connectOption);

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', () => console.log('DB connection successful'));
const dailySchema = require('./model/dailySchema');
const Daily = mongoose.model('daily', dailySchema, 'daily');
   
app.prepare()
.then(() => {
 const server = express()
 server.use(express.json());

 //ここから追加
 server.get('/index/get', async (req, res) => {
   const dailys = await Daily.find({});
   res.json(dailys);
 });
 //ここまで追加

 server.post('/addDaily/post', async (req, res) => {
   const daily = new Daily({
     title: req.body.title,
     content: req.body.content,
     created: Date.now(),
   });
   const sevedDaily = await daily.save();

   return app.render(req, res, '/addDaily', req.query)
 });
   
 server.get('*', (req, res) => {
   return handle(req, res)
 })
   
 server.listen(3000, (err) => {
   if (err) throw err
   console.log('> Ready on http://localhost:3000')
 })
})
.catch((ex) => {
 console.error(ex.stack)
 process.exit(1)
})

次に下記の様にindex.jsを編集していきます。

//index.js
import { Button , Row, Col, Card, ListGroup, ListGroupItem} from 'react-bootstrap';
import Header from "../components/Header"

//ここから編集
import fetch from 'node-fetch'

export default class index extends React.Component{
 static async getInitialProps(){
   const res = await fetch('http://127.0.0.1:3000/index/get')
   const posts = await res.json()
   return {posts}
 }

 render(){
   return(
     <div>
 
       <Header />
 
       <Row className="mt-2">
         <Col xs={12} md={{span: 6, offset: 3}}>
           <Button href="/addDaily" block>
             日記を追加する
           </Button>
         </Col>
       </Row>
       
       <Row className="mt-4">
        <Col xs={12} md={{span: 6, offset: 3}}>
          <Card>
            <Card.Header>日記一覧</Card.Header>
              <ListGroup className="list-group-flush">
                <ListGroupItem>
                 {this.props.posts.map(daily => (
                   <div>
                     <Card.Title>{daily.title}</Card.Title>
                     <Card.Subtitle className="mb-2 text-muted">
                       {daily.created}
                     </Card.Subtitle>
                     <Card.Text>
                       {daily.content}
                     </Card.Text>
                   </div>
                 ))}
                </ListGroupItem>
              </ListGroup>
          </Card>
        </Col>
      </Row>
     </div>
   );
 }
}
//ここまで編集

これでgetの設定はできましたので、npm run devでサーバーを立ち上げhttp://localhost:3000にアクセスすると下記の様に先ほど追加した日記が表示されていると思います。

スクリーンショット 2020-04-21 11.06.11

まとめ

以上でNext.js × Expressでの日記アプリ作成は終了です。

今回の日記アプリは一人で使うことを想定しているため、アカウントを作成する機能を作ってはいませんが応用として調べながら作ってみるのも面白いと思います。

プログラミング の世界はとても深く進化が激しいですが、この記事が一つの入り口になってくれることを願います。

参考


美味しいご飯に使わせてもらいますmm