Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,646 changes: 4,646 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
"start": "node src/index.js"
},
"dependencies": {
"aws-sdk": "^2.390.0",
"@aws-sdk/client-s3": "^3.213.0",
"@aws-sdk/s3-request-presigner": "^3.213.0",
"aws-sdk": "^2.1258.0",
"dotenv": "^6.2.0",
"express": "^4.16.4",
"mongoose": "^5.4.5",
"mongoose": "^6.7.2",
"morgan": "^1.9.1",
"multer": "^1.4.1",
"multer-s3": "^2.9.0"
Expand Down
115 changes: 115 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
[![rocket.jpg](https://i.postimg.cc/SRHcRS29/rocket.jpg)](https://postimg.cc/5QqXkMm9)

<h2 style="text-align: center;">Upload file Mutter + s3</h2>

### Tutorial BLOG Rocketseat:

> Link para o post no blog da Rocketseat -> [Upload de imagens no S3 da AWS com Node.js](https://blog.rocketseat.com.br/upload-de-imagens-no-s3-da-aws-com-node-js/ "Rocket")

### Descrição:

Vamos implementar uma API em Node.js que irá fazer upload de imagens em uma pasta temporária no servidor local e também no serviço S3 (Simple Storage Service) da AWS (Amazon Web Services). Iremos utilizar o MongoDB para armazenar os Posts que contém informações referente a imagem que será salva. Vamos disponibilizar as rotas para que o front end consuma a API.

S3 da AWS é um serviço altamente escalável e barato, que nos motiva utiliza-lo para arquivos estáticos. Custa menos dinheiro colocar arquivos no S3 do que no servidor em uma pasta temporária que consome o disco — Heroku, Digital Ocean, Umbler, entre outros.

Todavia, para um app de teste, claro que compensa manter nesses serviços.

Hoje já vamos aprender como usar S3, pode ser necessário para apps profissionais.

### Usando

- Comando para Clonar o repositorio

`$ git clone https://github.com/rocketseat-content/youtube-upload-nodejs-reactjs-backend.git `

- Entre dentro da pastar clonada

`$ cd youtube-upload-nodejs-reactjs-backend`

- Rode o comando yarn, caso não tenha o yarn instalado [clique aqui e instale seguindo essa dica!](https://www.youtube.com/watch?v=JvsGQnGE-xg "Clique aqui e instale seguindo essa dica !")

`$ yarn`

- Configure seu **mongoose**, adicione seu **.env**, **depois** rode esse comando.

`$ node src/index.js`

- Sevidor vai iniciar com a seguinte mensagem, **Obs** a porta e o ip e configurado pelo seu **.env**:

`Servidor rodando com o IP: XXX.XXX.XXX PORT: XXXX`

## Exemplos de .env

# Se hospedar sua aplicação em algum lugar, seu ip deverar ser 0.0.0.0
#Define o IP:
APP_IP=127.0.0.1
#Defina a PORTA:
APP_PORT=3000

# s3: para produção
# local: em desenvolvimento
STORAGE_TYPE=

# Pegue esses dados no site S3 AWS
# Defina seu bucket name
BUCKET_NAME=
# Defina seu bucket Access Key ID
AWS_ACCESS_KEY_ID=
# Defina sua Secret Acess Key
AWS_SECRET_ACCESS_KEY=
# Defina sua Região
AWS_DEFAULT_REGION=

# Pode ser da sua máquina local ou Mongo Atlas
MONGO_URL=

# 1 Error:

**Se caso ao usar o serviço s3 e lhe imprima o seguinte error:**

> **Status do error: 500, (Internal server error)**

**Descrição:**

> Algo parecido com -> **[this.client.send() is not a function]**

**Possivel solução:**

**Verifique as versões das dependencias necessarias no arquivo package.json**

"dependencies": {
"aws-sdk": "^2.390.0",
"multer": "^1.4.1",
"multer-s3": "^2.9.0"
}

Caso alguma dependencia esteja com versões diferente das citadas acima, mesmo em versões mais atualizadas,
edite seu arquivo **package.json** e troque as vesões das dependencias, **Deleta a pasta node_modules ** então rode o comando:

> `$ yarn`

**Possível causa:**

> Algumas versões mais recentes dessas dependencias, estão causando esse bug.

# 2 Error:

**Caso ao startar o sevidor, seja imprimido no terminal as seguintes mensagens:**

(node:19040) Warning: Accessing non-existent property 'count' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:19040) Warning: Accessing non-existent property 'findOne' of module exports inside circular dependency
(node:19040) Warning: Accessing non-existent property 'remove' of module exports inside circular dependency
(node:19040) Warning: Accessing non-existent property 'updateOne' of module exports inside circular dependency

**Remova o mongoose**

`$ yarn remove mongoose`

**Depois re-instale**

`$ yarn add mongoose`

**Possível causa:**

> Versão da dependencia mongoose e antiga!
15 changes: 15 additions & 0 deletions src/Backup code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* const AWS = require("aws-sdk");
const s3 = new AWS.S3();
AWS.config.update({
region: "us-east-1",
signatureVersion: "v4",
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
}); */

/* s3.getObject({
Bucket: process.env.BUCKET_NAME,
Key: post["key"],
})
.createReadStream()
.pipe(response); */
10 changes: 10 additions & 0 deletions src/config/aws.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* Configuração do AWS VERSÃO 2 */
const AWS = require("aws-sdk");
AWS.config.update({
region: process.env.AWS_DEFAULT_REGION,
credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY },
});

module.exports = {
AWS,
};
62 changes: 35 additions & 27 deletions src/config/multer.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,67 @@
/* Imports */
const multer = require("multer");
const path = require("path");
const crypto = require("crypto");
const aws = require("aws-sdk");
const AWSV2 = require("./aws");
const multerS3 = require("multer-s3");

/* Você pode selecionar o tipo de storage padrão no arquivo .env
pode ser s3 ou local
*/
const storageTypes = {
/* Storage Local */
local: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, path.resolve(__dirname, "..", "..", "tmp", "uploads"));
destination: (request, file, callback) => {
callback(null, path.resolve(__dirname, "..", "..", "tmp", "uploads"));
},
filename: (req, file, cb) => {
crypto.randomBytes(16, (err, hash) => {
if (err) cb(err);
filename: (request, file, callback) => {
crypto.randomBytes(16, (error, hash) => {
if (error) callback(error);

file.key = `${hash.toString("hex")}-${file.originalname}`;

cb(null, file.key);
callback(null, file.key);
});
}
},
}),

/* Storage s3 */
s3: multerS3({
s3: new aws.S3(),
s3: new AWSV2.AWS.S3(),
bucket: process.env.BUCKET_NAME,
contentType: multerS3.AUTO_CONTENT_TYPE,
acl: "public-read",
key: (req, file, cb) => {
crypto.randomBytes(16, (err, hash) => {
if (err) cb(err);
/* Se o seu bucket for
public -> acl: 'public'
privado -> acl: 'privado',
caso contrario irar dar um error de access denied'
*/
acl: "private",
key: (request, file, callback) => {
crypto.randomBytes(16, (error, hash) => {
if (error) callback(error);

const fileName = `${hash.toString("hex")}-${file.originalname}`;

cb(null, fileName);
callback(null, fileName);
});
}
})
},
}),
};

module.exports = {
dest: path.resolve(__dirname, "..", "..", "tmp", "uploads"),
storage: storageTypes[process.env.STORAGE_TYPE],
limits: {
fileSize: 2 * 1024 * 1024
fileSize: 2 * 1024 * 1024,
},
fileFilter: (req, file, cb) => {
const allowedMimes = [
"image/jpeg",
"image/pjpeg",
"image/png",
"image/gif"
];
/* Verifica o tipo de arquivo */
fileFilter: (request, file, callback) => {
const allowedMimes = ["image/jpeg", "image/pjpeg", "image/png", "image/gif"];

if (allowedMimes.includes(file.mimetype)) {
cb(null, true);
callback(null, true);
} else {
cb(new Error("Invalid file type."));
callback(new Error("Invalid file type."));
}
}
},
};
47 changes: 36 additions & 11 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
/* Imports */
require("dotenv").config();

/* Variaveis */
const express = require("express");
const morgan = require("morgan");
const mongoose = require("mongoose");
const path = require("path");
const cors = require("cors");

const app = express();
var mongooseConnectionStatus;

/* Strings: \x1b[32m, \x1b[34m \x1b[33m significa cores para quando imprimir
no terminal a mensagens ficarem colorida
*/

/**
* Database setup
*/
mongoose.connect(
process.env.MONGO_URL,
{
useNewUrlParser: true
(async () => {
try {
const db = await mongoose.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
});
mongooseConnectionStatus = true;
console.log(`\x1b[34m Database connected to: \x1b[32m${db.connection.name}`);
} catch (error) {
server.close((err) => {
console.log("Banco não está conectado servidor morrendo....");
process.exit(err ? 1 : 0);
});
}
);
})();

/* Add CORS */
app.use(cors());

/* Add JSON */
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan("dev"));
app.use(
"/files",
express.static(path.resolve(__dirname, "..", "tmp", "uploads"))
);
app.use("/files", express.static(path.resolve(__dirname, "..", "tmp", "uploads")));

/* Add Rotas */
app.use(require("./routes"));

app.listen(3000);
/* Tratamento de error 404 */
app.use(function (request, response, next) {
response.status(404).send("Esta rota não existe");
});

/* Start server */
const server = app.listen(process.env.APP_PORT, process.env.APP_IP, function () {
console.log(`\x1b[34m Servidor rodando com o \x1b[32m IP: ${process.env.APP_IP} \x1b[33m PORT: ${process.env.APP_PORT}`);
});

server.setTimeout(5000);
31 changes: 17 additions & 14 deletions src/models/Post.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
/* Imports */
const mongoose = require("mongoose");
const aws = require("aws-sdk");
const AWSV2 = require("../config/aws");
const fs = require("fs");
const path = require("path");
const { promisify } = require("util");

const s3 = new aws.S3();
/* Criar uma nova instancia da aws */
const s3 = new AWSV2.AWS.S3();

/* Define um schema para "TABELA" do mongoose */
const PostSchema = new mongoose.Schema({
name: String,
size: Number,
key: String,
url: String,
createdAt: {
type: Date,
default: Date.now
}
default: Date.now,
},
});

PostSchema.pre("save", function() {
/* Salva */
PostSchema.pre("save", function () {
if (!this.url) {
this.url = `${process.env.APP_URL}/files/${this.key}`;
}
});

PostSchema.pre("remove", function() {
/* Remove */
PostSchema.pre("remove", function () {
if (process.env.STORAGE_TYPE === "s3") {
return s3
.deleteObject({
Bucket: process.env.BUCKET_NAME,
Key: this.key
Key: this.key,
})
.promise()
.then(response => {
console.log(response.status);
.then((response) => {
console.log(response);
})
.catch(response => {
console.log(response.status);
.catch((response) => {
console.log(response);
});
} else {
return promisify(fs.unlink)(
path.resolve(__dirname, "..", "..", "tmp", "uploads", this.key)
);
return promisify(fs.unlink)(path.resolve(__dirname, "..", "..", "tmp", "uploads", this.key));
}
});

Expand Down
Loading