API Estacionamentos usando Expres.js + Atlas + swaggerUI

Leandro Gomes
29 min readMay 13, 2021

Esta API é trabalho final realizado no âmbito da UTC de Sistemas Distribuídos lecionada pelo professor Pedro Pinto, elaborado por: Frederico Cabral e Leandro Gomes.

Vamos criar uma API para gerir estacionamentos, para começar caso não tenhamos, vamos criar uma conta no Atlas, onde vamos criar um cluster para a nossa base de dados estar online.

Depois de termos conta no Atlas vamos então criar o nosso cluster, primeiro escolhemos o tipo de aplicação que vamos criar, depois a linguagem que queremos usar, como podemos ver na figura seguinte.

O Atlas tem uma opção free em que disponibilizam até 512 MB, e é este que vamos escolher, para a nossa API.

Depois escolhemos o serviço cloud que queremos associar à nossa Base de Dados, no nosso caso escolhemos o Azure, porque já temos conta criada lá, mas dá para usar também ou o Amazon aws ou o Google Cloud, depois selecionamos a região mais próxima da nossa localização, para reduzir os problemas de latência, no nosso caso como estamos em Portugal escolhemos, Netherlands (Holanda).

Mas a baixo na pagina vamos dar um nome ao nosso cluster como podemos ver na imagem seguinte.

Clicamos em Create Cluster.

Depois vamos ter a seguinte interface, onde vamos fazer os proximos passos para concluir a criação do nosso cluster.

De seguida vamos tratar do acesso à nossa Base de Dados.

Criamos um novo User.

Mais a baixo Clicamos em Add User.

O proximo passo é configurar o acesso a base de dados, clicamos em ALLOW ACCESS FROM ANYWHERE.

Para termos dados de exemplo na nossa Base de Dados, caso queiramos fazer alguns testes para verificar se está tudo a funcionar como esperado podemos escolher Load Sample Dataset, como podemos ver na figura seguinte.

Depois aparecerá uma janela para confirmarmos a criação de Dados de exemplo.

De seguida aparecerá uma interface onde podemos ver como está a nossa Base de dados.

Agora selecionamos a forma como queremos conectar-nos com a nossa Base de Dados, como estamos a desenvolver uma API a escolha será Connect your application, como podemos ver na figura seguinte.

Depois de clicar na opção Connect your application, vai nos aparecer o pedaço de código que será nescessário para fazer a coneção entre a nossa API e a nossa Base de Dados.

Código este que vamos colocar no ficheiro index.js do nosso projeto.

Mas antes disso vamos criar o nosso projeto, vamos criar a pasta do nosso projeto dando-lhe o nome de ApiEstacionamentos, depois entramos na pasta e através da CMD fazemos o seguinte comando, para darmos inicio ao nosso projeto.

npm init

E vamos preencher os dados da nossa API, com a seguinte informação com as devidas alterações.

De seguida instalamos as depêndencias que precisamos para o nosso projeto usando o seguinte comando.

npm install — save express mongoose nodemon swagger-ui-express

Destas dependências o nodemon, server para não termos que manualmente parar o servidor e ativa-lo outra vez, usando esta dependência cada vez que alteramos codigo o servidor é reiniciado, o que torna o desenvolvimento da API mais agil.

Para ser mais simples usar o nodemon, vamos ao ficheiro package.json e vamos atribuir-lhe um alias e o ficheiro package.json ficará assim.

Assim quando quisermos ativar o nosso servidor executamos o seguinte comando na CMD.

npm run start

Mas antes de colocarmos o nosso site ativo, vamos ao nosso ficheiro index.js, e vamos inserir o seguinte código.

//Framework express.jsconst express = require(‘express’);// to serve auto-generated swagger-ui generated API docs from expressconst swaggerUi = require(‘swagger-ui-express’);const swaggerDocument = require(‘./ViewSwagger/swagger.json’);//Porto Lógicoconst porto = 8081;//inicializacao das routesdos Administradoresconst MatriculasRoutes = require(“./routes/AdministracaoRoutes”);//inicializacao das routes do parqueconst ParqueRoutes = require(“./routes/ParqueRoutes”);//iniciar app expressconst app = express();//acesso a bdconst MongoClient = require(‘mongodb’).MongoClient;const uri = “mongodb+srv://TrabalhoEstacionamento:<password>@estacionamentos.l18xu.mongodb.net/EstacionamentoDB?retryWrites=true&w=majority”;const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });client.connect(err => {const collection = client.db(“test”).collection(“devices”);// perform actions on the collection objectclient.close();});app.use(‘/api’,swaggerUi.serve,swaggerUi.setup(swaggerDocument));app.use(“/”, routes);app.use(express.json());// Iniciar servidorapp.listen(porto, () => {console.log(‘Servidor a executar no porto ‘ + porto);});

No código anterior, a parte do acesso à base de dados não resultou como esperado, a ligação à base de dados é feita através do pacote mongoDB, que é uma drive nativa para interagir com o MongoDB, deste modo a comunicação com a base de dados é feita com os comandos que usariamos na Mongo-shell, no entanto vamos fazer as alterações nescessárias para usarmos o pacote mongoose, que é uma ferramenta para modelar objectos para a MongoDB, ou seja o mongoose foi criado por cema da driver da MongoDB, para uma mais facil modelação dos dados, para mais explicações sobre o uso do mongoDB ou do mongoose clique aqui.

//Framework express.jsconst express = require(‘express’);// to serve auto-generated swagger-ui generated API docs from expressconst swaggerUi = require(‘swagger-ui-express’);const swaggerDocument = require(‘./ViewSwagger/swagger.json’);//Porto Lógicoconst porto = 8081;//inicializacao das routesdos Administradoresconst MatriculasRoutes = require(“./routes/AdministracaoRoutes”);//inicializacao das routes do parqueconst ParqueRoutes = require(“./routes/ParqueRoutes”);//iniciar app expressconst app = express();//acesso a bd/*const MongoClient = require(‘mongodb’).MongoClient;const uri = “mongodb+srv://TrabalhoEstacionamento:<password>@estacionamentos.l18xu.mongodb.net/EstacionamentoDB?retryWrites=true&w=majority”;const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });client.connect(err => {const collection = client.db(“test”).collection(“devices”);// perform actions on the collection objectclient.close();});*///import mongoose libraryconst mongoose = require(‘mongoose’);//acesso a mongoDBlet url = “mongodb+srv://TrabalhoEstacionamento:<password>@estacionamentos.l18xu.mongodb.net/EstacionamentoDB?retryWrites=true&w=majority”;let mongoDB = process.env.MONGODB_URI || url;mongoose.connect(mongoDB,{useNewUrlParser: true,useUnifiedTopology: true});mongoose.Promise = global.Promise;let db = mongoose.connection;db.on(‘error’, console.error.bind(console, ‘Erro na ligação a MongoDB!’));app.use(‘/api’,swaggerUi.serve,swaggerUi.setup(swaggerDocument));app.use(“/Administracao”, MatriculasRoutes);app.use(“/Parque”, ParqueRoutes);app.use(express.json());// Iniciar servidorapp.listen(porto, () => {console.log(‘Servidor a executar no porto ‘ + porto);});

Agora vamos criar as pastas que precisamos para termos o nosso projeto organizado em Models, Views, Controllers e as Routes (caminho para os controllers)executando o seguinte código na CMD, dentro da pasta do nosso projeto.

mkdir models viewSwagger controllers routes

Vamos a pasta models e vamos criar os models para a nossa API começamos por criar o ficheiro LugaresModel.js e vamos inserir o seguinte o modelo para a nossa coleção Lugares.

const mongoose = require(‘mongoose’);const Schema = mongoose.Schema;let LugaresSchema = new Schema({_id: {type: Number,generated: false,default: 1},qtd: {type: String,required: true},maximo: {type: String,required: true}});//Exportar o modelomodule.exports = mongoose.model(‘Lugares’, LugaresSchema);

Depois criamos o ficheiro MatriculasModel.js e vamos inserir o modelo para a nossa coleção de Matriculas.

const mongoose = require(‘mongoose’);const Schema = mongoose.Schema;let MatriculasSchema = new Schema({_id: {type: Number,generated: false,default: 1},nMatricula: {type: String,required: true}});//Exportar o modelomodule.exports = mongoose.model(‘Matriculas’, MatriculasSchema);

Depois vamos criar o ficheiro RegistoEntradasModel.js e vamos inserir o modelo para a nossa coleção de RegistosEntradas.

const mongoose = require(‘mongoose’);const Schema = mongoose.Schema;let RegistoEntradasSchema = new Schema({_id: {type: Number,generated: false,default: 1},matricula: {type: String,required: true},dataEntrada: {type: String,required: true},dataEntradaInv: {type: String,required: true},horaEntrada: {type: String,required: true},registada: {type: Boolean,required: true},lotacao: {type: Number,required: true},nEntrada: {type: Number,required: true}});//Exportar o modelomodule.exports = mongoose.model(‘RegistoEntradas’, RegistoEntradasSchema);

Agora vamos a pasta controllers e criamos o ficheiro ParqueController.js e vamos inserir o seguinte código.

var LugaresModel = require (‘../models/LugaresModel’);var RegistoEntradasModel = require(‘../models/RegistoEntradasModel’);var MatriculaModel = require (‘../models/MatriculasModel’);exports.LugaresVagos = function(req, res){LugaresModel.findOne({},function(err, lVagos){res.send(lVagos.qtd);})}exports.RegistaEntrada = async function(req, res){//Data do sistemalet timeStamp = Date.now();let dataTime = new Date(timeStamp);/*let dia = dataTime.getDate();let mes = dataTime.getMonth()+1;let ano = dataTime.getFullYear();let horas = dataTime.getHours();let minutos = dataTime.getMinutes();let segundos = dataTime.getSeconds();*///formatar a data e hora para stringlet dia = dataTime.getDate() + ‘/’ + (dataTime.getMonth()+1) + ‘/’ + dataTime.getFullYear();let horas = dataTime.getHours() + ‘:’ + dataTime.getMinutes()//colocar a matricula em maiusculas para prevenir desleixo do utilizadorlet matriculaInserir = req.params.matricula.toUpperCase();//averiguar se a matricula está registadaMatriculaModel.countDocuments({nMatricula: matriculaInserir},function(err, qtdmatricula){//saber qual o ultimo id de entrada de modo a ficar sequencialRegistoEntradasModel.findOne().sort(‘-_id’).exec(function(err,ultimoID){//saber qual a lotacao atual do parqueLugaresModel.findById(1, function(err,lugares){//saber quantos carros entraram no dia em que o carro está a entrarRegistoEntradasModel.countDocuments({dataEntrada: dia},function(err, entrada){entrada=entrada+1;//preparar o id do registolet correnteID=0;if(ultimoID == null){correnteID=0;}else{correnteID = parseInt(‘’ + ultimoID.id, 10);}correnteID=correnteID+1;//verificar existencia da matricula nos registoslet Mregistada=true;if(qtdmatricula<=0){matriculaInserir=’-’;Mregistada=false;}let auxlugar = parseInt(‘’ + lugares.qtd, 10);let registo = new RegistoEntradasModel({_id: correnteID,matricula: matriculaInserir,dataEntrada: dia,dataEntradaInv: dataTime.getFullYear() + ‘/’ + (dataTime.getMonth()+1) + ‘/’ + dataTime.getDate(),horaEntrada: horas,registada: Mregistada,lotacao: auxlugar,nEntrada: entrada})auxlugar= auxlugar -1;//registo da nova entradaregisto.save(function (err){if(err){throw err;}//atualizacao da lotacao do parquelugares.qtd=auxlugarlugares.save(function (err){if(err){throw err;}})})res.send(‘Entrada no dia ‘ + dia + ‘ e as ‘ + horas + ‘ horas registada com sucesso!’)})})})})}exports.RegistaSaida = function(req, res){LugaresModel.findOne({}, function(err, saida){let lug = parseInt(‘’ + saida.qtd, 10)saida.qtd = lug + 1;//atualizacao da lotacao do parquesaida.save(function(err){if(err){throw err;}})res.send(‘Saida registada com sucesso!’)})}exports.MediaCarros = async function(req, res){let periodo = req.params.periodo;//quantidade de entradas registadasRegistoEntradasModel.countDocuments({}, function(err, registoEntradas){//descobrir o primeiro registo da base de dadosRegistoEntradasModel.findOne({},{_id: 0, dataEntrada: 1}).sort(‘_id’).exec(function(err, datainicio){//descobrir o ultimo registo da base de dadosRegistoEntradasModel.findOne({},{_id: 0, dataEntrada: 1}).sort(‘-_id’).exec(function(err, datafim){let diaMillis = 86400000;let mesMillis = 2628000000;let anoMillis = 31536000000;datainicio = datainicio.dataEntrada;datafim = datafim.dataEntrada;var datePartinicio = datainicio.split(“/”);// month is 0-based, that’s why we need dataParts[1] — 1var dateObject = new Date(+datePartinicio[2], datePartinicio[1] — 1, +datePartinicio[0]);var datePartsfim = datafim.split(“/”);// month is 0-based, that’s why we need dataParts[1] — 1var dateObjects = new Date(+datePartsfim[2], datePartsfim[1] — 1, +datePartsfim[0]);//variavel de divisao para o calculovar Millis = diaMillis;if(req.params.periodo == “meses”){Millis = mesMillis;}else if(req.params.periodo == “anos”){Millis = anoMillis;}var resultado = Math.trunc((dateObjects-dateObject) / Millis);//total de carros a dividir pelo numero de dias / meses / anosregistoEntradas = Math.trunc((registoEntradas / resultado)*100)/100;/*console.log(“Primeiro registo: “+datainicio);console.log(“Ultimo registo: “+datafim);console.log(‘’ + periodo + ‘ entre as duas datas: ‘ + resultado);*/res.send(‘’ + periodo + ‘ entre as duas datas: ‘ + resultado +’ a média de caros por ‘+ req.params.periodo + ‘ é: ‘ + registoEntradas)})})})};exports.QtdDia = function(req, res){RegistoEntradasModel.find({dataEntrada: req.params.data},function(err,registos){res.send(registos);})}exports.QtdNRegistados = function(req, res){RegistoEntradasModel.find({dataEntrada: req.params.data, matricula: ‘-’},function(err,registos){res.send(registos);})}exports.MaiorDia = async function(req, res){//descobrir o maximo de entradas por diaRegistoEntradasModel.aggregate([{$group: {“_id”:”$dataEntrada”,entrada: {$max: ‘$nEntrada’}}}],function(err,maximosE){//adaptado de https://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value 02/05/2021function ordenar(a,b){if(a.entrada < b.entrada){return 1;}if(a.entrada > b.entrada){return -1;}return 0;}//ordena os dadosmaximosE.sort(ordenar);//remove os dados que nao tenham o campo entrada desejadomaximosE = maximosE.filter(p => p.entrada == maximosE[0].entrada);res.send(maximosE);});}exports.MenorDia = async function(req, res){//descobrir o maximo de entradas por diaRegistoEntradasModel.aggregate([{$group: {“_id”:”$dataEntrada”,entrada: {$max: ‘$nEntrada’}}}],function(err,registos){//adaptado de https://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value 02/05/2021function ordenar(a,b){if(a.entrada < b.entrada){return -1;}if(a.entrada > b.entrada){return 1;}return 0;}//ordena os dadosregistos.sort(ordenar);//remove os dados que nao tenham o campo entrada desejadoregistos=registos.filter(a => a.entrada == registos[0].entrada);res.send(registos);});}exports.QtdDiaCarro = async function(req, res){let data = req.params.data;let matricula = req.params.matricula.toUpperCase();RegistoEntradasModel.countDocuments({dataEntrada: data, matricula: matricula}, function(err, resultado){res.send(‘O carro pesquisado entrou ‘ + resultado + ‘ vezes no dia ‘ + data)})}exports.QtdPeriodo = function(req, res){let dataInicio = req.params.DataInicio;let dataFim = req.params.DataFim;RegistoEntradasModel.countDocuments({$and:[{dataEntrada:{$gte: dataInicio}},{dataEntrada:{$lte: dataFim}}]}, function(err, nCarros){res.send(‘Entre as datas inseridas entraram: ‘ + nCarros + ‘ carros.’);})}exports.DiasLotado = function(req, res){RegistoEntradasModel.find({lotacao: {$lte:’0'}},function(err,registos){res.send(registos);})}

Depois vamos criar o ficheiro AdministracaoController.js e vamos inserir o seguinte código.

var MatriculaModel = require (‘../models/MatriculasModel’);var LugaresModel = require (‘../models/LugaresModel’);var RegistoEntradasModel = require(‘../models/RegistoEntradasModel’);//populate de matriculasexports.AddMatriculas = async function(req, res){let quantidade = req.params.nfor(i=1; i<=quantidade; i++){//gera a matricula caracter a caracter aleatoriamentelet numeroa = Math.floor(Math.random() * (9)) ;let numerob = Math.floor(Math.random() * (9)) ;let numeroc = Math.floor(Math.random() * (9)) ;let numerod = Math.floor(Math.random() * (9)) ;let letraa = Math.floor(Math.random() * (91–65)) + 65;let letrab = Math.floor(Math.random() * (91–65)) + 65;/* — — — — — — — — — — possivel melhoria: nao introduzir matriculas iguais(procura matricula a inserir se existir voltar a gerar)*///formata a matricula para ser inseridalet registo = new MatriculaModel({_id: i,nMatricula: ‘’ + numeroa + numerob + ‘-’ + String.fromCharCode(letraa) +String.fromCharCode(letrab) + ‘-’ + numeroc + numerod,});//insere a matricularegisto.save(function(err){if(err){throw err;}})}res.send(‘Populate completo, pode ter de aguardar alguns minutos para estar acecivel na BD sao ‘ + (i-1) + ‘ dados’+ ‘\n’ + ‘Nao desligue o servidor ou a importacao dos dados será cancelada!’)}//apaga todas as matriculas registadasexports.DelMatriculas = function(req, res){MatriculaModel.remove(function(err){if(err){throw err;}res.send(‘Matriculas Apagadas com sucesso!’)})}//populate de registo de entradasexports.AddEstacionamentos = async function(req, res){//todas as matriculas registadasMatriculaModel.find({},function(req, TodasMatriculas){//lotacao do parqueLugaresModel.findById(1,function(req, registo){let lugares = parseInt(‘’ + registo.maximo, 10);let PEntradas = 50;let LMinimo = -5;let data = new Date();let dia = data.getDate();let mes = data.getMonth()+1;let ano = data.getFullYear();let hoje = dia + ‘/’ + mes + ‘/’ + ano;//data inicial é o dia 1 de janeiro de 2 anos antes do atuallet inicio = new Date();inicio.setFullYear(inicio.getFullYear() — 2,0,1);let diaI = inicio.getDate();let mesI = inicio.getMonth()+1;let anoI = inicio.getFullYear();let introduz = diaI + ‘/’ + mesI + ‘/’ + anoI;let introduzInv = anoI + ‘/’ + mesI + ‘/’ + diaI;let vagas = lugares;let correnteID=1//ciclo para percorrer desde a data inicial até a data atualwhile(hoje != introduz){// valor aleatorio de entradas no dia a registarlet entradas = Math.floor(Math.random()*(lugares+20)+1);//inicializacao da quantidade de carros que entram no dialet entrada = 1//ciclo para registar as entradas do dia a introduzirfor(i=1; i<=entradas; i++){//variavel aleatoria para saber se vai registar uma entradalet tipo=Math.floor(Math.random()*100+1)//forca nao haver saidas ou entradas de maisif(vagas < LMinimo && tipo <= PEntradas){tipo=100}else if(vagas == lugares && tipo > PEntradas){tipo=1}//regista entrada ou atualiza a lotacao com a saidaif(tipo <= PEntradas){let horas = data.getHours() + ‘:’ + data.getMinutes()//registar entrada de uma matricula conhecida ou desconhecidaif(Math.floor(Math.random()*100+1)<=80){//escolher uma matricula aleatoria para registar a entradalet posicaoMatricula = Math.floor(Math.random()*((TodasMatriculas.length-1)+1))matriculaInserir=TodasMatriculas[posicaoMatricula].nMatriculaMregistada=true}else{matriculaInserir=’-’;Mregistada=false}let NovaEntrada = new RegistoEntradasModel({_id: correnteID,matricula: matriculaInserir,dataEntrada: introduz,dataEntradaInv: introduzInv,horaEntrada: horas,registada: Mregistada,lotacao: vagas,nEntrada: entrada})NovaEntrada.save(function (err){if(err){throw err;}})//atualizacao de variaveisvagas=vagas-1entrada = entrada+1correnteID=correnteID+1}else{vagas=vagas+1}}//atualizacao do dia a introduzirinicio.setDate(inicio.getDate() + 1);diaI = inicio.getDate();mesI = inicio.getMonth()+1;anoI = inicio.getFullYear();introduz = diaI + ‘/’ + mesI + ‘/’ + anoI;introduzInv = anoI + ‘/’ + mesI + ‘/’ + diaI;}res.send(‘Populate completo, pode ter de aguardar alguns minutos para estar acecivel na BD sao ‘ + (correnteID-1) + ‘ dados’+ ‘\n’ + ‘Nao desligue o servidor ou a importacao dos dados será cancelada!’)})})}exports.DelEstacionamentos = function(req, res){RegistoEntradasModel.remove(function(err){if(err){throw err;}res.send(‘Matriculas Apagadas com sucesso!’)})}exports.AddMatricula = async function(req, res){let matriculaInserir = req.params.matricula.toUpperCase();MatriculaModel.findOne().sort('-_id').exec(function(err,ultimoID){//formata a matricula para ser inseridalet registo = new  MatriculaModel({_id: (parseInt('' + ultimoID.id, 10)+1),nMatricula: matriculaInserir,});registo.save(function(err){if(err){throw err;}})res.send('Matricula Registada com sucesso!')})}exports.ResetParque = async function(req, res){let quantidade = req.params.nLugaresModel.findById(1, function (err, registo) {if(registo == null){registo = new LugaresModel({_id: 1,qtd: quantidade,maximo: quantidade});}else{registo.qtd = quantidaderegisto.maximo = quantidade}//resetregisto.save(function(err){if(err){throw err;}})res.send(‘reset feito com sucesso!’)})}

Agora passamos para a pasta routes e vamos criar as routes para o nosso projeto, começamos por criar o ficheiro ParqueRoutes.js e adicionamos o seguinte código.

const express = require(“express”);const router = express.Router();//invocar o controllerconst parque_controller = require(‘../controllers/ParqueController’);//route Lugares Vagosrouter.route(“/LugaresVagos”).get(parque_controller.LugaresVagos);//route Registo de entrada de um carrorouter.route(“/RegistaEntrada/:matricula”).put(parque_controller.RegistaEntrada);//route Registo de saida de um carrorouter.route(“/RegistaSaida”).put(parque_controller.RegistaSaida);//route mediarouter.route(“/MediaCarros/:periodo”).get(parque_controller.MediaCarros);//route quantos carros entraram num certo diarouter.route(“/QtdCarrosNumaData/:data”).get(parque_controller.QtdDia);//route quantos carros nao registados entraram num certo diarouter.route(“/QtdCarrosNRegistadosNumaData/:data”).get(parque_controller.QtdNRegistados);//route MaisCarrosrouter.route(“/DiaComMaisCarros”).get(parque_controller.MaiorDia);//route MenosCarrosrouter.route(“/DiaComMenosCarros”).get(parque_controller.MenorDia);//route entradas do Carro num diarouter.route(“/EntradasCarroNumaData/:matricula/:data”).get(parque_controller.QtdDiaCarro);//route numero de carros num periudorouter.route(“/CarrosEntreDatas/:DataInicio/:DataFim”).get(parque_controller.QtdPeriodo);//route Registo de saida de um carrorouter.route(“/DiasLotado”).get(parque_controller.DiasLotado);module.exports = router;

Depois vamos criar o ficheiro AdministracaoRoutes.js e adicionamos o seguinte código.

const express = require(“express”);const router = express.Router();//invocar o controllerconst administracao_controller = require(‘../controllers/AdministracaoController’);//route popular matriculasrouter.route(“/PopularMatriculas/:n”).post(administracao_controller.AddMatriculas);//route Apaga matriculasrouter.route(“/DelMatriculas”).delete(administracao_controller.DelMatriculas);//route popular estacionamentosrouter.route(“/PopularEstacionamentos”).post(administracao_controller.AddEstacionamentos);//route Apaga estacionamentosrouter.route(“/DelEstacionamentos”).delete(administracao_controller.DelEstacionamentos);//route inserir matricularouter.route("/RegistaMatricula/:matricula").post( administracao_controller.AddMatricula);//route Reset ao parquerouter.route(“/ResetParque/:n”).put(administracao_controller.ResetParque);module.exports = router;

Falta agora tratarmos da view da nossa API, para isso vamos a pasta viewSwagger e vamos criar o ficheiro swagger.json, onde vamos configurar a UI da nossa API.

{“swagger”: “2.0”,“info”: {“title”: “API Estacionamentos”,“description”: “API para gerir estacionamentos”,“version”: “1.0”},“host”: “localhost:8081”,“basePath”: “/”,“schemes”: [“http”],“paths”: {“/Administracao/PopularMatriculas/{n}”: {“post”: {“tags”: [“Administracao”],“description”: “Quantas matriculas pretende inserir?”,“operationId”: “Inserir matriculas na Base de Dados”,“parameters”: [{“name”: “n”,“in”: “path”,“description”: “Numero de matriculas a inserir”,“required”: true}],“responses”: {}}},“/Administracao/DelMatriculas”: {“delete”: {“tags”: [“Administracao”],“description”: “Apagar todas as matriculas”,“operationId”: “Apagar todas Matriculas na Base de Dados”,“responses”: {}}},“/Administracao/PopularEstacionamentos”: {“post”: {“tags”: [“Administracao”],“description”: “Vai popular o estacionamento com 2 anos”,“operationId”: “Inserir estacionamentos na Base de Dados”,“responses”: {}}},“/Administracao/DelEstacionamentos”: {“delete”: {“tags”: [“Administracao”],“description”: “Apagar todos os estacionamentos”,“operationId”: “Apagar todos os estacionamentos na Base de Dados”,“responses”: {}}},“/Administracao/ResetParque/{n}”: {“put”: {“tags”: [“Administracao”],“description”: “Reset ao parque”,“operationId”: “Reset ao parque”,“parameters”: [{“name”: “n”,“in”: “path”,“description”: “inserir o numero de lugares vagos”,“required”: true,“default”: “150”}],“responses”: {}}},“/Parque/LugaresVagos”: {“get”: {“tags”: [“Lugares Vagos”],“description”: “Lugares vagos no parque”,“operationId”: “Lugares vagos no parque”,“responses”: {}}},“/Parque/RegistaEntrada/{matricula}”: {“put”: {“tags”: [“Parque”],“description”: “Regista Entrada de um carro”,“operationId”: “Regista Entrada de um carro”,“parameters”: [{“name”: “matricula”,“in”: “path”,“description”: “Registo de entrada de um carro”,“required”: true}],“responses”: {}}},“/Parque/RegistaSaida”: {“put”: {“tags”: [“Parque”],“description”: “Regista Saida de um carro”,“operationId”: “Regista Saida de um carro”,“responses”: {}}},“/Parque/MediaCarros/{periodo}”: {“get”: {“tags”: [“Parque”],“description”: “Media de carros por num periodo”,“operationId”: “Ver a media de carros num periodo”,“parameters”: [{“name”: “periodo”,“in”: “path”,“description”: “tipo de periodo para a media”,“required”: true,“enum”: [“dias”,“meses”,“anos”]}],“responses”: {}}},“/Parque/QtdCarrosNumaData/{data}”: {“get”: {“tags”: [“Parque”],“description”: “Numero de carros que entraram num certo dia”,“operationId”: “Ver o numero de carros que entraram num certo dia”,“parameters”: [{“name”: “data”,“in”: “path”,“description”: “data”,“required”: true}],“responses”: {}}},“/Parque/QtdCarrosNRegistadosNumaData/{data}”: {“get”: {“tags”: [“Parque”],“description”: “Numero de carros não registados que entraram num certo dia”,“operationId”: “Ver o numero de carros não registados que entraram num certo dia”,“parameters”: [{“name”: “data”,“in”: “path”,“description”: “data”,“required”: true}],“responses”: {}}},“/Parque/DiaComMaisCarros”: {“get”: {“tags”: [“Parque”],“description”: “Dia do Parque em que houve mais entradas”,“operationId”: “Dia com mais carros”,“responses”: {}}},“/Parque/DiaComMenosCarros”: {“get”: {“tags”: [“Parque”],“description”: “Dia do Parque em que houve menos entradas”,“operationId”: “Dia com menos carros”,“responses”: {}}},“/Parque/EntradasCarroNumaData/{matricula}/{data}”: {“get”: {“tags”: [“Parque”],“description”: “Numero de entradas de um carro num determinado dia”,“operationId”: “Numero de entradas dum carro numa data”,“parameters”: [{“name”: “matricula”,“in”: “path”,“description”: “Matricula do carro que pretende pesquisar as entradas”,“required”: true},{“name”: “data”,“in”: “path”,“description”: “Dia que pretende pesquisar”,“required”: true}],“responses”: {}}},“/Parque/CarrosEntreDatas/{DataInicio}/{DataFim}”: {“get”: {“tags”: [“Parque”],“description”: “Numero de carros num certo intervalo de datas”,“operationId”: “Numero de carros num certo periodo”,“parameters”: [{“name”: “DataInicio”,“in”: “path”,“description”: “Data inicial da pesquisa”,“required”: true},{“name”: “DataFim”,“in”: “path”,“description”: “Data Final da Pesquisa”,“required”: true}],“responses”: {}}},“/Parque/DiasLotado”: {“get”: {“tags”: [“Parque”],“description”: “Dias em que o estacionamento ficou lotado”,“operationId”: “Dias em que o estacionamento ficou lotado”,“responses”: {}}}}}

Vamos agora ativar o servidor.

A Interface da API deverá ficar assim.

Depois de termos a API criada e a funcionar, vamos agora coloca-la num servidor da cloud, vamos criar uma maquina virtual no Azure da microsoft, para alojar a nossa API, criamos uma VM (Virtual Machine) adequada as nossas necessidades, no nosso caso criamos a seguinte maquina.

Depois de ter a VM criada precisamos criar uma porta de entrada para o nosso servidor.

Ao criar uma porta de entrada, devemos escolher a porta que usamos na fase de desenvolvimento da nossa API.

Depois de termos criado a porta de entrada vamos ligar a nossa VM da seguinte forma.

Clicando em iniciar ou então através da app para smartphones que é muito intuitiva, para a usarmos basta lermos com o smartphone o QRCode e depois controlar os nossos servidores a partir da app.

Agora vamos usar o putty, para entrarmos na nossa VM e depois podermos clonar o nosso projeto e também para automatizarmos o arranque da nossa API, primeiro instalamos o putty, depois abrimo-lo e vamos inserir o IP publico da nossa máquina, para controlarmos remotamente a nossa VM.

Inserimos o IP publico da nossa VM, a porta 22 que é a que está atribuída ao SSH selecionamos o tipo de ligação SSH, e clicamos Open, de seguida abrirá uma consola onde temos que validar a nossa entrada com o username e password que definimos quando criamos a nossa VM.

Uma vez dentro da nossa máquina executamos os seguintes códigos para que a nossa API corra sem problemas, começamos por atualizar o nosso ubuntu executando o seguinte comando.

sudo apt-get update

Assim que acabe executamos o comando.

sudo apt-get upgrade

Depois vamos instalar o node.js .

sudo apt install nodejs

Conferimos a versão do nosso node.js com o seguinte comando.

node -v

Este comando devolve-nos a versão do node que está instalada que devera ser a v14.16.1, caso seja uma anterior podem executar o seguinte comando para atualizar a versão.

curl -sL https://deb.nodecurl -sL https://deb.nodesource.com/setup_14.x | sudo -E bashsource.com/setup_14.x | sudo -E bash

Depois fazemos o clone do nosso projeto através do seguinte comando.

git clone https//github.com/utilizador/projeto

Após termos o projeto na nossa máquina, vamos ativar o servidor para testarmos se conseguimos aceder através de outra máqaquina, executando o mesmo comando como se fosse para ativarmos o servidor localmente com o seguinte comando.

node indes.js

Se estiver tudo bem configurado se colocarmos o seguinte url.

http://20.90.113.135:8081/api/

Vamos entrar na nossa API.

Cada vez que queremos colocar o servidor ativo temos que aceder a nossa VM remotamente usando o putty, depois entrar na pasta do projeto e executar o comando node index.js, o que é um pouco chato, ter que fazer sempre estes passos, então de seguida vamos configurar o nosso servidor para que o servidor fique ativo automaticamente quando o ativamos por exemplo através da app para smartphones do Azure, para isso vamos executar os seguintes comandos na nossa VM através do putty.

Entramos na pasta donosso projeto e vamos começar a inserir os comandos para automatizar a ativação do nosso servidor.

sudo npm install pm2@lastest -g

Este comando faz com que o npm instale o modulo globaly, para que esteja disponivél em todo o sistema.

pm2 start index.js

Com este comando adicionamos o nosso ficheiro index.js a lista de processos do pm2, que é gerada sempre que a máquina é ligada.

Output[PM2] Spawning PM2 daemon with pm2_home=/home/ubuntu/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/ubuntu/ApiEstacionamentos/index.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤
│ index │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ubuntu│ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

Como podemos ver o pm2 cria um App name com o nome do ficheiro sem a extensão js e atribui-lhe também um id, todos os Aplicativos que estão a funcionar sob o pm2 são automaticamente reiniciados se o aplicativo falhar ou se for encerrado, mas podemos fazer melhor, fazendo o aplicativo iniciar logo na inicialização do sistema com o subcomando startup. Este subcomando gera e configura um script de inicialização para iniciar o pm2 e os seus processos geridos na inicialização do servidor.

pm2 startup systemd

Ao executar este comando o output por ele gerado, vamos copiar a ultima linha, que inclui um comando para ser executado com privilégios de superutilizador para definir o pm2 para inicializar na inicialização do sistema.

Output[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu — hp /home/ubuntu

Copiamos a linha a negrito, colamos na CMD e executamos.

sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu — hp /home/ubuntu

Depois guardamos a lista de processos do pm2 e os ambientes correspondentes com o seguinte comando.

pm2 save

Acabamos de criar uma unidade systemd que executa o pm2 para o nosso user na inicialização do sistema, a istancia pm2 que por sua vez executa o index.js.

Agora vamos iniciar o serviço através do seguinte comando.

sudo systemctl start pm2-ubuntu

Para verificarmos o estado da unidade systemd executamos o seguinte comando.

systemctl status pm2-ubuntu

Depois reiniciamos a VM e esperamos alguns minutos para que fique tudo operacional e depois assim que iniciamos a VM ou na conta do Azure ou na App a nossa API fica logo disponível para os utilizadores.

Depois iniciamos a nossa VM e vamos explorar a API

Com as funções de Administrador (/Administracao/PopularMatriculas/{n} e
​/Administracao​/PopularEstacionamentos), adicionamos vários documentos as coleções da nossa Base de Dados para podermos agora mostrar o resultado obtido por cada uma das funções

Se executarmos a função “/Parque/LugaresVagos”, a API vai devolver-nos quantos lugares estão vagos no estacionamento como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/MediaCarros/{periodo}”, a API vai devolver-nos a média de caros que entraram no estacionamento durante um dia, ou mês ou ano, que podemos selecionar no dropdown de tipo de periodo para a média, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/QtdCarrosNumaData/{data}”, a API vai devolver-nos os carros que entraram no estacionamento numa data, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/QtdCarrosNRegistadosNuma Data/{data}”, a API vai devolver-nos os carros não registados que entraram numa data, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/DiaComMaisCarros”, a API vai devolver-nos o dia em que entraram mais carros no estacionamento, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/DiaComMenosCarros”, a API vai devolvernos o dia em que entraram menos carros no estacionamento, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/EntradasCarroNumaData/{matricula}/{data}”, a API vai devolver-nos a quantidade de vezes que um carro entrou no estacionamento numa data, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/CarrosEntreDatas/{DataInicio}/{DataFim}”, a API vai devolver-nos a quantidade carros que entraram no estacionamento entre duas datas, como podemos ver na imagem seguinte.

Se executarmos a função “/Parque/DiasLotado”, a API vai devolver-nos as datas em que o estacionamento esteve lotado, como podemos ver na imagem seguinte.

Agora vamos tratar da autenticação e dos privilégios da nossa API, para que o Utilizador simples não tenha os mesmos privilégios que o Administrador, para isso vamos começar por instalar a dependência do JWT (JsonWebToken), executando o seguinte comando na CMD.

npm install jsonwebtoken -save

Vamos começar por criar o modelo para a nossa coleção dos Users, criamos o ficheiro UserModel.js dentro da pasta models, e inserimos o seguinte código.

const mongoose = require(‘mongoose’);const Schema = mongoose.Schema;let UsersSchema = new Schema({_id: {type: Number,generated: false,default: 1},username: {type: String,required: true},password: {type: String,required: true},role: {type: String,required: true},});//Exportar o modelomodule.exports = mongoose.model(‘Users’, UsersSchema);Agora vamos criar o ficheiro UserController.js, na pasta controllers e inserimos o seguinte código.var User = require(‘../models/UserModel’);//JWT (para gerar e verificar tokens)const jwt = require(‘jsonwebtoken’);//importar o secret para o JWT do ficheiro Secret.jsonconst Secret= require(‘../Secret.json’);const SECRET_UTILIZADORES = Secret.SECRET_UTILIZADORES;const SECRET_ADMINISTRADOR = Secret.SECRET_ADMINISTRADOR;//criar um novo utilizadorexports.newUser = function(req, res){User.countDocuments({username: req.params.username}, function(err, contador){if(contador == 0){User.findOne().sort(‘-_id’).exec(function(err, userID){let aux = 1;let aux_role=”utilizador”if(userID != null){aux = parseInt(‘’+ userID.id, 10);aux = aux + 1;aux_role=”utilizador”}else{aux_role=”administrador”}let user = new User({_id: aux,username: req.params.username,password: req.params.password,role: aux_role});user.save(function(err){if(err){throw err;}//console.log(‘user criado com sucesso.’);res.send(‘User inserido com sucesso!’);})})}else{//console.log(‘esse username já existe!’);res.send(‘Esse username já existe!’);}})};//fazer login na APIexports.login = function(req, res) {let userName = req.params.username;let pass = req.params.password;User.countDocuments({username: userName, password: pass}, function(err, contagem){if(contagem != 0){User.findOne({username: userName, password: pass}, function(err, utilizador){if(userName == utilizador.username && pass == utilizador.password){let idUsers = utilizador.id;let aux_role = utilizador.role;//jwt.sign({payload(info para saber qual é o usuario)}, process.env.Assinatura digital,{opcoes “tempo expiracao”})let token = jwt.sign({idUser: idUsers}, SECRET_UTILIZADORES,{expiresIn: 300});if(aux_role==’administrador’){token = jwt.sign({idUser: idUsers}, SECRET_ADMINISTRADOR,{expiresIn: 300});}return res.json({Login: “valido”, token: token});}})}else{res.status(500).json({message: ‘Login inválido!’});}})};

De seguida vamos criar o ficheiro UserRoutes.js, na pasta routes e vamos inserir o seguinte código.

const express = require(‘express’);const router = express.Router();const user_controller = require(‘../controllers/UserController’);function verificaJWTAdmin(req, res, next){//alterar nome para adminprevilegiosconst token = req.headers[‘api_key’];jwt.verify(token, SECRET_ADMINISTRADOR, (err) => {if(err){return res.status(401).send(‘Unautorized access!’);}next();})}//criar um novo userrouter.route(“/NovoUtilizador/:username/:password”).post(verificaJWTAdmin, user_controller.newUser);//loginrouter.route(“/login/:username/:password”).post(user_controller.login);module.exports = router;

Agora vamos criar o ficheiro Secret.json na raiz do projeto, onde vamos guardar o secret que vai ser usado na criação da token, para isso inserimos o seguinte código.

{“SECRET_UTILIZADORES”: “utilizadores”,“SECRET_ADMINISTRADOR”: “administradores”}

Agora vamos ao ficheiro index.js e vamos substituir o código do index.js pelo seguinte onde já estão as alterações para que a nossa API use as routes referentes aos users.

//Framework express.jsconst express = require(‘express’);// to serve auto-generated swagger-ui generated API docs from expressconst swaggerUi = require(‘swagger-ui-express’);const swaggerDocument = require(‘./ViewSwagger/swagger.json’);//Porto Lógicoconst porto = 8081;//inicializacao das routesdos Administradoresconst MatriculasRoutes = require(“./routes/AdministracaoRoutes”);//inicializacao das routes do parqueconst ParqueRoutes = require(“./routes/ParqueRoutes”);//inicializacao das routes dos usersconst UserRoutes = require(“./routes/UserRoutes”);//iniciar app expressconst app = express();//import mongoose libraryconst mongoose = require(‘mongoose’);//acesso a mongoDBlet url = “mongodb+srv://TrabalhoEstacionamento:<password>@estacionamentos.l18xu.mongodb.net/EstacionamentoDB?retryWrites=true&w=majority”;let mongoDB = process.env.MONGODB_URI || url;mongoose.connect(mongoDB,{useNewUrlParser: true,useUnifiedTopology: true});mongoose.Promise = global.Promise;let db = mongoose.connection;db.on(‘error’, console.error.bind(console, ‘Erro na ligação a MongoDB!’));app.use(‘/api’,swaggerUi.serve,swaggerUi.setup(swaggerDocument));app.use(“/Administracao”, MatriculasRoutes);app.use(“/Parque”, ParqueRoutes);app.use(“/Utilizador”, UserRoutes);app.use(express.json());// Iniciar servidorapp.listen(porto, () => {console.log(‘Servidor a executar no porto ‘ + porto);});

Depois vamos ao ficheiro ParqueRoutes.js e substituímos o código pelo seguinte.

const express = require("express");const router = express.Router();//JWT (para gerar e verificar tokens)const jwt = require('jsonwebtoken');//importar o secret para o JWT do ficheiro Secret.jsonconst Secret= require('../Secret.json');const SECRET_UTILIZADORES=Secret.SECRET_UTILIZADORES;const SECRET_ADMINISTRADOR=Secret.SECRET_ADMINISTRADOR;//invocar o controllerconst parque_controller = require('../controllers/ParqueController');//verifica previlégios administradosfunction verificaJWTAdmin(req, res, next){const token = req.headers['api_key'];jwt.verify(token, SECRET_ADMINISTRADOR, (err) => {if(err){return res.status(401).send('Unautorized access!');}next();})}
//verifica previlégios todos os users registadosfunction verificaJWTTodos(req, res, next){let token = req.headers['api_key'];jwt.verify(token, SECRET_ADMINISTRADOR, (err) => {if(err){jwt.verify(token, SECRET_UTILIZADORES, (err) => {if(err){return res.status(401).send('Unautorized access!');}next();})//return res.status(401).send('Unautorized access!');}else{next();}})}//route Lugares Vagos todos os utilizadoresrouter.route("/LugaresVagos").get(verificaJWTTodos, parque_controller.LugaresVagos);//route Registo de entrada de um carro adminrouter.route("/RegistaEntrada/:matricula").put(verificaJWTAdmin, parque_controller.RegistaEntrada);//route Registo de saida de um carro adminrouter.route("/RegistaSaida").put(verificaJWTAdmin, parque_controller.RegistaSaida);//route media adminrouter.route("/MediaCarros/:periodo").get(verificaJWTAdmin, parque_controller.MediaCarros);//route quantos carros entraram num certo dia adminrouter.route("/QtdCarrosNumaData/:data").get(verificaJWTAdmin, parque_controller.QtdDia);//route quantos carros nao registados entraram num certo dia adminrouter.route("/QtdCarrosNRegistadosNumaData/:data").get(verificaJWTAdmin, parque_controller.QtdNRegistados);//route MaisCarros adminrouter.route("/DiaComMaisCarros").get(verificaJWTAdmin, parque_controller.MaiorDia);//route MenosCarros adminrouter.route("/DiaComMenosCarros").get(verificaJWTAdmin, parque_controller.MenorDia);//route entradas do Carro num dia adminrouter.route("/EntradasCarroNumaData/:matricula/:data").get(verificaJWTAdmin, parque_controller.QtdDiaCarro);//route numero de carros num periudo adminrouter.route("/CarrosEntreDatas/:DataInicio/:DataFim").get(verificaJWTAdmin, parque_controller.QtdPeriodo);//route Registo de saida de um carro adminrouter.route("/DiasLotado").get(verificaJWTAdmin, parque_controller.DiasLotado);module.exports = router;

Agora vamos ao ficheiro AdministracaoRoutes.js e substituimos o código pelo seguinte.

const express = require("express");const router = express.Router();//invocar o controllerconst administracao_controller = require('../controllers/AdministracaoController');//JWT (para gerar e verificar tokens)const jwt = require('jsonwebtoken');//importar o secret para o JWT do ficheiro Secret.jsonconst Secret= require('../Secret.json');const SECRET_ADMINISTRADOR=Secret.SECRET_ADMINISTRADOR;//verifica previlégios administradorfunction verificaJWTAdmin(req, res, next){const token = req.headers['api_key'];jwt.verify(token, SECRET_ADMINISTRADOR, (err) => {if(err){return res.status(401).send('Unautorized access!');}next();})}//route popular matriculasrouter.route("/PopularMatriculas/:n").post(verificaJWTAdmin, administracao_controller.AddMatriculas);//route Apaga matriculasrouter.route("/DelMatriculas").delete(verificaJWTAdmin, administracao_controller.DelMatriculas);//route popular estacionamentosrouter.route("/PopularEstacionamentos").post(verificaJWTAdmin, administracao_controller.AddEstacionamentos);//route Apaga estacionamentosrouter.route("/DelEstacionamentos").delete(verificaJWTAdmin, administracao_controller.DelEstacionamentos);//route inserir matricularouter.route("/RegistaMatricula/:matricula").post(verificaJWTAdmin, administracao_controller.AddMatricula);//route Reset ao parquerouter.route("/ResetParque/:n").put(verificaJWTAdmin, administracao_controller.ResetParque);module.exports = router;

Agora vamos ao ficheiro swagger.json e vamos substituir o codigo pelo seguinte.

{"openapi": "3.0.0","info": {"title": "API Estacionamentos","description": "API para gerir estacionamentos","version": "1.0"},"host": "20.90.113.135:8081","basePath": "/","schemes": ["http"],"paths": {"/Utilizador/login/{username}/{password}": {"post": {"tags": ["Utilizadores"],"description": "Login","operationId": "Login","parameters": [{"name": "username","in": "path","description": "insira o seu nome de utilizador","required": true},{"name": "password","in": "path","description": "insira a sua password","schema":{"type": "string","format": "password"},"required": true}],"responses": {}}},"/Utilizador/NovoUtilizador/{username}/{password}": {"post": {"tags": ["Utilizadores"],"description": "Criar novo user","operationId": "Criar novo user","parameters": [{"name": "username","in": "path","description": "insira um nome de utilizador","required": true},{"name": "password","in": "path","description": "insira uma password","schema":{"type": "string","format": "password"},"required": true}],"responses": {},"security": [{"api_key": []}]}},"/Administracao/PopularMatriculas/{n}": {"post": {"tags": ["Administracao"],"description": "Quantas matriculas pretende inserir?","operationId": "Inserir matriculas na Base de Dados","parameters": [{"name": "n","in": "path","description": "Numero de matriculas a inserir","required": true,"default": "10000"}],"responses": {},"security": [{"api_key": []}]}},"/Administracao/DelMatriculas": {"delete": {"tags": ["Administracao"],"description": "Apagar todas as matriculas","operationId": "Apagar todas Matriculas na Base de Dados","responses": {},"security": [{"api_key": []}]}},"/Administracao/PopularEstacionamentos": {"post": {"tags": ["Administracao"],"description": "Vai popular o estacionamento com 2 anos","operationId": "Inserir estacionamentos na Base de Dados","responses": {},"security": [{"api_key": []}]}},"/Administracao/DelEstacionamentos": {"delete": {"tags": ["Administracao"],"description": "Apagar todos os estacionamentos","operationId": "Apagar todos os estacionamentos na Base de Dados","responses": {},"security": [{"api_key": []}]}},"/Administracao/RegistaMatricula/{matricula}": {"post": {"tags": ["Administracao"],"description": "Registo da matricula de um carro","operationId": "Regist da matricula de um carro","parameters": [{"name": "matricula","in": "path","description": "Registo da matricula de um carro","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Administracao/ResetParque/{n}": {"put": {"tags": ["Administracao"],"description": "Reset ao parque","operationId": "Reset ao parque","parameters": [{"name": "n","in": "path","description": "inserir o numero de lugares vagos","required": true,"default": "150"}],"responses": {},"security": [{"api_key": []}]}},"/Parque/LugaresVagos": {"get": {"tags": ["Lugares Vagos"],"description": "Lugares vagos no parque","operationId": "Lugares vagos no parque","responses": {},"security": [{"api_key": []}]}},"/Parque/RegistaEntrada/{matricula}": {"put": {"tags": ["Parque"],"description": "Regista Entrada de um carro","operationId": "Regista Entrada de um carro","parameters": [{"name": "matricula","in": "path","description": "Registo de entrada de um carro","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Parque/RegistaSaida": {"put": {"tags": ["Parque"],"description": "Regista Saida de um carro","operationId": "Regista Saida de um carro","responses": {},"security": [{"api_key": []}]}},"/Parque/MediaCarros/{periodo}": {"get": {"tags": ["Parque"],"description": "Media de carros por num periodo","operationId": "Ver a media de carros num periodo","parameters": [{"name": "periodo","in": "path","description": "tipo de periodo para a media","required": true,"schema":{"type": "string","enum": ["dias","meses","anos"]}}],"responses": {},"security": [{"api_key": []}]}},"/Parque/QtdCarrosNumaData/{data}": {"get": {"tags": ["Parque"],"description": "Numero de carros que entraram num certo dia","operationId": "Ver o numero de carros que entraram num certo dia","parameters": [{"name": "data","in": "path","description": "data","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Parque/QtdCarrosNRegistadosNumaData/{data}": {"get": {"tags": ["Parque"],"description": "Numero de carros não registados que entraram num certo dia","operationId": "Ver o numero de carros não registados que entraram num certo dia","parameters": [{"name": "data","in": "path","description": "data","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Parque/DiaComMaisCarros": {"get": {"tags": ["Parque"],"description": "Dia do Parque em que houve mais entradas","operationId": "Dia com mais carros","responses": {},"security": [{"api_key": []}]}},"/Parque/DiaComMenosCarros": {"get": {"tags": ["Parque"],"description": "Dia do Parque em que houve menos entradas","operationId": "Dia com menos carros","responses": {},"security": [{"api_key": []}]}},"/Parque/EntradasCarroNumaData/{matricula}/{data}": {"get": {"tags": ["Parque"],"description": "Numero de entradas de um carro num determinado dia","operationId": "Numero de entradas dum carro numa data","parameters": [{"name": "matricula","in": "path","description": "Matricula do carro que pretende pesquisar as entradas","required": true},{"name": "data","in": "path","description": "Dia que pretende pesquisar","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Parque/CarrosEntreDatas/{DataInicio}/{DataFim}": {"get": {"tags": ["Parque"],"description": "Numero de carros num certo intervalo de datas","operationId": "Numero de carros num certo periodo","parameters": [{"name": "DataInicio","in": "path","description": "Data inicial da pesquisa","required": true},{"name": "DataFim","in": "path","description": "Data Final da Pesquisa","required": true}],"responses": {},"security": [{"api_key": []}]}},"/Parque/DiasLotado": {"get": {"tags": ["Parque"],"description": "Dias em que o estacionamento ficou lotado","operationId": "Dias em que o estacionamento ficou lotado","responses": {},"security": [{"api_key": []}]}}},"components": {"securitySchemes": {"api_key": {"type": "apiKey","name": "api_key","in": "header"}}},"security": {"api_key": []}}

Depois de acrescentar os utilizadores a nossa API deverá ficar assim.

Agora vamos fazer o pull do repositório para o nosso servidor, para isso usamos o seguinte comando dentro da pasta do nosso projeto.

git pull https://github.com/utilizador/ApiEstacionamentos

Depois na consola do putty aparecerá para inserir o username e a password do github, depois de confirmar o username e password, vai fazer o update do projeto.

Falta agora apenas testar a autenticação e os privilégios de cada utilizador.

Da maneira que definimos a autenticação da nossa API, a única função que pode ser acedida sem a autenticação é a do login, para cada utilizador se autenticar, com a token, para que tenha perdições consoante o tipo de utilizador que é, vamos primeiro experimentar utilizar uma função de administração sem estarmos autenticados, a qual não devemos ter acesso.

Como esperado deu erro de acesso não autorizado, agora vamos experimentar a função para ver os lugares vagos, que pode ser utilizada pelo utilizador comum.

Mais uma vez acesso não autorizado, ou seja não podemos consultar nada sobre o parque de estacionamento se não formos utilizadores registados do parque.

Agora vamos autenticarmo-nos como um utilizador comum e tentar aceder a uma função de administração.

Usamos um login valido e foi nos gerada a token para nos autenticarmos.

Agora vamos tentar saber a media de carros por mês.

Mais uma vez foi nos negado o acesso, agora vamos tentar ver quantos lugares temos vagos no parque.

Como esperado recebemos a resposta de quantos lugares estão vagos.

Agora vamos fazer login como administrador.

E vamos ver se conseguimos ver os lugares vagos.

Para terminarmos os nossos testes vamos tentar saber a media de carros por mês.

E se formos administradores conseguimos saber a media de carros por mês, informação a qual não temos acesso autenticados como utilizador comum.

Este projeto está disponivél no repopsitório do github.

--

--

Leandro Gomes

Estudante de Engenharia Informática do Instituto Politécnico da Guarda.