Artigo original: How To Make create-react-app work with a Node Back-end API

Esta é uma pergunta muito comum entre os novos desenvolvedores do React. É uma pergunta que eu tinha quando estava começando com o React e o Node.js. Neste breve exemplo, mostrarei como fazer com que o create-react-app funcione com o back-end com o Node.js e o Express.

create-react-app

Crie um projeto usando create-react-app.

npx create-react-app example-create-react-app-express

Crie um diretório /client no diretório example-create-react-app-express e mova todo o código boilerplate do React criado pelo create-react-app para esse novo diretório client.

cd example-create-react-app-express
mkdir client

O servidor com Node e Express

Crie um arquivo package.json dentro do diretório raiz (example-create-react-app-express) e copie o seguinte conteúdo:

{
  "name": "example-create-react-app-express",
  "version": "1.0.0",
  "scripts": {
    "client": "cd client && yarn start",
    "server": "nodemon server.js",
    "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
  },
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4"
  },
  "devDependencies": {
    "concurrently": "^4.0.1"
  }
}

Observe que estou usando concurrently para executar a aplicação do React e o servidor ao mesmo tempo. O marcador –kill-others-on-fail eliminará outros processos se um deles for encerrado com um código de status diferente de zero.

Instale o nodemon globalmente e as dependências do servidor:

npm i nodemon -g
yarn

Crie um arquivo server.js e copie o seguinte conteúdo:

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
const port = process.env.PORT || 5000;

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/api/hello', (req, res) => {
  res.send({ express: 'Hello From Express' });
});

app.post('/api/world', (req, res) => {
  console.log(req.body);
  res.send(
    `I received your POST request. This is what you sent me: ${req.body.post}`,
  );
});

app.listen(port, () => console.log(`Listening on port ${port}`));

Este é um servidor Express simples que será executado na porta 5000 e terá duas rotas de API: GET - /api/hello e POST -/api/world.

Nesse ponto, você pode executar o servidor Express com o seguinte comando (ainda dentro do diretório raiz):

node server.js

Agora, navegue até http://localhost:5000/api/hello e você verá o seguinte:

TPcEMDY475EhrLyGruM9uWQvM33ZKlDAl-cb

Vamos testar a rota POST quando criarmos a aplicação em React.

A aplicação em React

Agora, vá para o diretório do client onde está a nossa aplicação em React.

Adicione a seguinte linha ao arquivo package.json criado pelo create-react-app.

"proxy": "http://localhost:5000/"

A chave para usar um servidor de back-end do Express com um projeto criado com create-react-app é usar um proxy. Isso informa ao servidor de desenvolvimento do webpack para fazer proxy das nossas solicitações de API para o nosso servidor de API, já que o nosso servidor do Express está sendo executado em localhost:5000.

Agora, modifique o ./client/src/App.js para chamar o back-end da API Express. As alterações estão em negrito.

import React, { Component } from 'react';

import logo from './logo.svg';

import './App.css';

class App extends Component {
  state = {
    response: '',
    post: '',
    responseToPost: '',
  };
  
  componentDidMount() {
    this.callApi()
      .then(res => this.setState({ response: res.express }))
      .catch(err => console.log(err));
  }
  
  callApi = async () => {
    const response = await fetch('/api/hello');
    const body = await response.json();
    if (response.status !== 200) throw Error(body.message);
    
    return body;
  };
  
  handleSubmit = async e => {
    e.preventDefault();
    const response = await fetch('/api/world', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ post: this.state.post }),
    });
    const body = await response.text();
    
    this.setState({ responseToPost: body });
  };
  
render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
        <p>{this.state.response}</p>
        <form onSubmit={this.handleSubmit}>
          <p>
            <strong>Post to Server:</strong>
          </p>
          <input
            type="text"
            value={this.state.post}
            onChange={e => this.setState({ post: e.target.value })}
          />
          <button type="submit">Submit</button>
        </form>
        <p>{this.state.responseToPost}</p>
      </div>
    );
  }
}

export default App;

Criamos o método callApi para interagir com o caminho do GET da API do Express. Depois, chamamos esse método em componentDidMount e, por fim, definimos o estado para a resposta da API, que será "Hello From Express".

Observe que não usamos um URL totalmente qualificado http://localhost:5000/api/hello para chamar nossa API, mesmo que nossa aplicação do React seja executada em uma porta diferente (3000). Isso se deve à linha do proxy que adicionamos ao arquivo package.json anteriormente.

Temos um formulário com uma única entrada. Quando enviado, chama handleSubmit, que, por sua vez, chama o caminho POST do Express API, salva a resposta no estado e exibe uma mensagem para o usuário: I received your POST request. This is what you sent me: [message from input].

Agora, abra o arquivo ./client/src/App.css e modifique a classe .App-header da seguinte forma (alterações em negrito)

.App-header {
...
  min-height: 50%;
...
  padding-bottom: 10px;
}

Executando a aplicação

Se o servidor ainda estiver em execução, interrompa-o pressionando Ctrl+C no terminal.

No diretório raiz do projeto, execute o seguinte:

yarn dev

Isso iniciará a aplicação do React e executará o servidor ao mesmo tempo.

Agora, navegue até http://localhost:3000 e você verá a aplicação do React exibindo a mensagem proveniente do nosso caminho GET do Express. Legal!

v3LAoDh50Yq4c60yOY69WpRwnZL2fRCIXfTs
Exibição do caminho GET

Agora, digite algo no campo de entrada e envie o formulário. Você verá a resposta do caminho POST do Express exibida logo abaixo do campo de entrada.

NcLZDJaVE0g833Xrn8jM2G8e5f4LVVygt10O
Chamada do caminho POST

Por fim, dê uma olhada no seu terminal e verá a mensagem que enviamos do client, porque chamamos console.log no corpo da solicitação no caminho POST Express.

r43BMtm-aiA84Nxrin1eTHXi4YnnEX3SYzMM
Node

Implementação de produção no Heroku

Abra o server.js e substitua pelo conteúdo a seguir:

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');

const app = express();
const port = process.env.PORT || 5000;

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// API calls
app.get('/api/hello', (req, res) => {
  res.send({ express: 'Hello From Express' });
});

app.post('/api/world', (req, res) => {
  console.log(req.body);
  res.send(
    `I received your POST request. This is what you sent me: ${req.body.post}`,
  );
});

if (process.env.NODE_ENV === 'production') {
  // Serve any static files
  app.use(express.static(path.join(__dirname, 'client/build')));
    
  // Handle React routing, return all requests to React app
  app.get('*', function(req, res) {
    res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
  });
}

app.listen(port, () => console.log(`Listening on port ${port}`));

Abra o arquivo ./package.json e adicione o seguinte à entrada de scripts

"start": "node server.js",
"heroku-postbuild": "cd client && npm install && npm install --only=dev --no-shrinkwrap && npm run build"

O Heroku executará o script start por padrão e isso servirá à nossa aplicação. Em seguida, queremos instruir o Heroku a criar nossa aplicação do client. Fazemos isso com o script heroku-postbuild.

Agora, vá até o Heroku (em inglês) e faça login (ou abra uma conta, se ainda não tiver uma).

Crie uma aplicação e dê um nome a ela.

YSsjVCvWV0-uieTxyQG1TDLrDT4ZxjOTb4pP
"Create new app" no Heroku

Clique na aba Deploy e siga as instruções de implantação (que eu acho que são bastante autoexplicativas, não há motivo para repeti-las aqui).

vFyFAdbumn-k-39zK9DFZLJ6oWS9vfflmH1N
Deploy de uma aplicação no Heroku

É isso! Você pode abrir sua aplicação clicando no botão Open app, no canto superior direito do painel do Heroku da sua aplicação.

Outras opções de implementação

Escrevo sobre outras opções de implementação aqui:

  • Netlify (em inglês)
  • Now (em inglês)
  • Heroku (explicação mais detalhada - em inglês)

Estrutura do projeto

Esta será a estrutura final do projeto:

YSFfgasf0j6pDjUX5TgcGCW6b8m74M6DTnY9

Acesse o código completo no repositório do GitHub.

Obrigado pela leitura! Espero que você tenha gostado.

Você pode seguir o autor no Twitter, GitHub, Medium, LinkedIn ou em todos eles.

Esta postagem foi publicada originalmente no blog pessoal do autor.


Atualização em 25/08/19: o autor estava em processo de desenvolver uma aplicação para web de orações, chamada "My Quiet Time - A Prayer Journal". Para ver algumas capturas de tela de modelos, acesse o link a seguir: http://pc.cd/Lpy7. Se quiser saber mais sobre a aplicação, o autor deixou disponível o endereço no Twitter para dúvidas sobre a aplicação.