Demoção ao vivo : link
Saltar para o que há de novo?
Um caldeira para aplicativos da Web Node.js.
Se você participou de algum hackathons no passado, sabe quanto tempo leva para iniciar um projeto: decida sobre o que construir, escolha uma linguagem de programação, escolha uma estrutura da web, escolha uma estrutura CSS. Um tempo depois, você pode ter um projeto inicial no GitHub e só então outros membros da equipe podem começar a contribuir. Ou que tal fazer algo tão simples quanto fazer login com a autenticação do Facebook ? Você pode gastar horas se não estiver familiarizado com o funcionamento do OAuth 2.0.
Quando iniciei esse projeto, meu foco principal estava na simplicidade e na facilidade de uso . Também tentei torná -lo o mais genérico e reutilizável possível para cobrir a maioria dos casos de uso de aplicativos da Web Hackathon, sem serem muito específicos. Na pior das hipóteses, você pode usar isso como um guia de aprendizado para seus projetos, se, por exemplo, você estiver interessado apenas em entrar no Google Authentication e nada mais.
"Bom! Esse leia sozinho já é ouro!"
- Adrian Le Bas
"Incrível. Simplesmente incrível."
- Steven Rueter
"Estou usando isso há um ano e muitos projetos, é um caldeira incrível e o projeto está bem mantido!"
- Kevin Granger
“Small World With Sahat's Project. Estávamos usando seu iniciante de hackathon para o nosso hackathon no fim de semana passado e recebemos alguns prêmios. Repos realmente úteis!”
- Entrevista candidato a uma das empresas com as quais trabalhava.
MongoDB (instalação local ou hospedado)
Node.js 18+
Ferramentas da linha de comando
Mac OS X: Xcode (ou OS X 10.9+ : xcode-select --install )
Windows: Código do Visual Studio + Subsistema Windows para Linux - Ubuntu ou Visual Studio
Ubuntu / Linux Mint: sudo apt-get install build-essential
Fedora : sudo dnf groupinstall "Development Tools"
OpenSUSE: sudo zypper install --type pattern devel_basis
Nota: Se você é novo no Node ou Express, poderá encontrar Node.js & Express From Scratch Series para aprender o básico do Node e Express. Como alternativa, aqui está outro ótimo tutorial para iniciantes completos - começar com o Node.js, Express, MongoDB.
Etapa 1: A maneira mais fácil de começar é clonar o repositório:
# Get the latest snapshot
git clone https://github.com/sahat/hackathon-starter.git myproject
# Change directory
cd myproject
# Install NPM dependencies
npm install
# Then simply start your app
node app.js NOTA: Eu recomendo a instalação do Nodemon. Ele observa quaisquer alterações no seu aplicativo Node.js e reinicia automaticamente o servidor. Depois de instalado, em vez de node app.js , use nodemon app.js Ele economizará muito tempo a longo prazo, porque você não precisará reiniciar manualmente o servidor sempre que fizer uma pequena alteração no código. Para instalar, execute sudo npm install -g nodemon .
Etapa 2: Obtenha as teclas da API e altere as configurações, se necessário após concluir a Etapa 1 e instalar localmente o MongoDB, você poderá acessar o aplicativo através de um navegador da Web e usar contas de usuário locais. No entanto, certas funções como as integrações da API podem não funcionar corretamente até obter chaves específicas de provedores de serviços. As chaves fornecidas no projeto servem como espaço reservado e você pode mantê -las para os recursos que não está utilizando no momento. Para incorporar as chaves adquiridas no aplicativo, você tem duas opções:
export assim: export FACEBOOK_SECRET=xxxxxx . Esse método é considerado uma prática melhor, pois reduz o risco de incluir acidentalmente seus segredos em um repositório de código..env.example : abra o arquivo .env.example e atualize as chaves do espaço reservado com as recém -adquiridas. Este método tem o risco de verificação acidental de seus segredos nos repositórios de código.O que obter e configurar:
Smtp
Recaptcha
OAuth para logins sociais (entre com / login com)
As chaves da API para provedores de serviços nos exemplos da API, se você planeja usá -las.
Atlas MongoDB
Endereço de email
NGROK e HTTPS Se você deseja usar alguma API que precise do HTTPS para funcionar (por exemplo, Pinterest ou Facebook), você precisará baixar o NGROK. Inicie o ngrok, defina seu base_url no endereço de encaminhamento (ou seja, https://3ccb-1234-abcd.ngrok-free.app ) e use o endereço de encaminhamento para acessar seu aplicativo. Se você estiver usando um proxy como o NGROK, poderá obter um erro de incompatibilidade do CSRF se tentar acessar o aplicativo em http://localhost:8080 em vez do endereço https: //...ngrok-free.app.
Depois de instalar ou baixar o cliente NGROK independente, você pode iniciar o NGROK para interceptar os dados trocados na porta 8080 com ./ngrok http 8080 no linux ou ngrok http 8080 no Windows.
Etapa 3: desenvolva seu aplicativo e personalize a experiência
Etapa 4: Opcional - Implante na produção, consulte:
Você precisará obter credenciais apropriadas (ID do cliente, segredo do cliente, chave da API ou nome de usuário e senha) para a API e o serviço fornece o que você precisa. Consulte a Etapa 2 na seção de início para obter mais informações.
Obtenha credenciais SMTP de um provedor para e -mails transacionais. Defina as variáveis de ambiente SMTP_USER, SMTP_PASSWORD e SMTP_HOST de acordo. Ao escolher o host SMTP, lembre -se de que o aplicativo está configurado para usar transmissões SMTP seguras sobre a porta 465 pronta para uso. Você tem a flexibilidade de selecionar qualquer provedor que atenda às suas necessidades ou aproveite um dos seguintes fornecedores, cada um oferecendo um nível gratuito para sua conveniência.
| Provedor | Nível grátis | Site |
|---|---|---|
| SendGrid | 100 e -mails/dia de graça | https://sendgrid.com |
| Smtp2go | 1000 e -mails/mês gratuitamente | https://www.smtp2go.com |
| Brevo | 300 e -mails/dia de graça | https://www.brevo.com |
.env . Essas chaves estarão acessíveis em configurações, as teclas de recaptcha suspensas se você precisar delas novamente mais tardehttp://localhost:8080 , etc)http://localhost:8080/auth/google/callback ).envhttp://localhost:8080/auth/snapchat/callback ).env.env.env.envlocalhost sob domínios de aplicativoshttp://localhost:8080 , etc) em URL do sitehttp://localhost:8080/auth/facebook/callback ) em URIs de redirecionamento OAuth válido NOTA: Após uma inscrição bem-sucedida no Facebook, um usuário será redirecionado de volta para a página inicial com hash #_=_ no URL. Não é um bug. Veja esta discussão sobre o pilhas para obter maneiras de lidar com isso.
http://localhost:8080 , etc) como o URL da página inicial.http://localhost:8080/auth/github/callback ).envhttp://localhost:8080 , etc).http://localhost:8080/auth/twitter/callback ).envhttp://localhost:8080/auth/linkedin/callback )http://localhost:8080 , etc).r_basicprofile.env.env.envhttp://localhost:8080/auth/foursquare/callback ).envhttp://localhost:8080/auth/tumblr/callback ).env.envhttp://localhost:8080/auth/twitch/callback ).env.env.env ..env | Nome | Descrição |
|---|---|
| config /passport.js | Passaporte Estratégias locais e OAuth, além de middleware de login. |
| controladores /api.js | Rota do controlador para /API e todos os exemplos de API. |
| controladores /contact.js | Controlador para formulário de contato. |
| Controllers /home.js | Controlador para página inicial (índice). |
| Controllers /User.JS | Controlador para gerenciamento de contas de usuário. |
| Models /User.JS | Esquema de Mongoose e modelo para o usuário. |
| público / | Ativos estáticos (fontes, CSS, JS, IMG). |
| public / js /application.js | Especifique dependências JavaScript do lado do cliente. |
| public / js /pp.js | Coloque seu JavaScript do lado do cliente aqui. |
| Public / css /main.scss | Principal de estilos de estilos para o seu aplicativo. |
| visualizações /conta / | Modelos para login, redefinição de senha, inscrição, perfil . |
| visualizações /api / | Modelos para exemplos de API. |
| visualizações /parciais /flash.pug | Erro, informações e notificações de flash de sucesso e sucesso. |
| visualizações /parciais /header.pug | Modelo parcial da barra naval. |
| visualizações /parciais /footer.pug | Modelo parcial do rodapé. |
| Views /layout.pug | Modelo base. |
| visualizações /home.pug | Modelo de página inicial. |
| .dockerignore | Pasta e arquivos ignorados pelo uso do Docker. |
| .env.example | Suas chaves da API, fichas, senhas e URI de banco de dados. |
| .EsLinTrc | Regras para Eslint Linter. |
| .gitignore | Pasta e arquivos ignorados pelo git. |
| App.js | O arquivo de aplicativo principal. |
| docker-compose.yml | Docker Compõe o arquivo de configuração. |
| Dockerfile | Arquivo de configuração do Docker. |
| package.json | Dependências do NPM. |
| pacote lock.json | Contém versões exatas das dependências do NPM no package.json. |
Nota: Não há preferência por como você nomeia ou estrutura suas visualizações. Você pode colocar todos os seus modelos em um diretório views de nível superior, sem ter uma estrutura de pastas aninhada, se isso facilitar as coisas para você. Só não se esqueça de atualizar extends ../layout e os caminhos res.render() correspondentes nos controladores.
| Pacote | Descrição |
|---|---|
| @Fortawesome/Fontawesome Free | Biblioteca de símbolo e ícone. |
| @googleapis/drive | Biblioteca de integração de API do Google Drive. |
| @googleapis/sheets | Google Sheets API Integration Library. |
| @ladjs/bootstrap-social | Biblioteca de botões sociais. |
| @lob/lob-typeScript-sdk | LOB (Serviço de Correio / Mailamento Físico do USPS). |
| @node-rs/bcrypt | Biblioteca para senhas de usuário de hash e salga. |
| @Octokit/Rest | Biblioteca API do Github. |
| @passaporte-js/passaporte-twitter | X (Twitter) Suporte de login (OAuth 2). |
| @popperjs/núcleo | Biblioteca JS de front -end para poppers e dicas de ferramentas. |
| Axios | Cliente http. |
| PARSURADOR DE CORPO | Node.js Body Parsing Middleware. |
| Bootstrap | Estrutura CSS. |
| Chai | Biblioteca de asserção BDD/TDD. |
| Cheerio | Raspe as páginas da web usando sintaxe no estilo jQuery. |
| compressão | Middleware de compactação node.js. |
| Connect-Mongo | MongoDB Session Store para Express. |
| dotenv | Carrega variáveis de ambiente do arquivo .env. |
| ErrorHandler | Middleware do manipulador de erros somente para desenvolvimento. |
| Eslint | Linter JavaScript. |
| Eslint-config-airbnb-Base | Configuração Eslint pelo Airbnb. |
| Eslint-Plugin-chai | Torna as declarações de Eslint para Chai.js 'esperam' e 'deveriam'. |
| Eslint-Plugin-Import | Eslint Plugin com regras que ajudam a validar as importações adequadas. |
| expressar | Node.js Web Framework. |
| Express-Flash | Fornece mensagens flash para expresso. |
| limite de taxa expressa | Middleware limitador da taxa para proteção de abuso. |
| sessão expressa | Middleware de sessão simples para expresso. |
| Husky | Git Hook Manager para automatizar tarefas com o Git. |
| jQuery | Biblioteca JS front-end para interagir com elementos HTML. |
| lastfm | Biblioteca da API last.fm. |
| etapa de fiapos | Utilidade para fiapos de arquivos encenados pelo git. |
| LOB | Biblioteca LOB API. |
| Lodash | Uma biblioteca de utilitários para trabalhar com matrizes, números, objetos, strings. |
| LUSCA | Middleware CSRF. |
| MailChecker | Verifica se um endereço de email é válido e não é um endereço descartável. |
| Mocha | Estrutura de teste. |
| momento | Analisar, validar, calcular datas e horários. |
| MongoDBMemoryServer | MongoDB na memória (para executar testes sem um banco de dados em execução). |
| mangusto | MONGODB ODM. |
| Morgan | Http solicitar middleware de logger para node.js. |
| Multer | Middleware node.js para lidar com multipart/form-data . |
| NodeMailer | Biblioteca Node.js para enviar e -mails. |
| NYC | Teste de cobertura. |
| passaporte | Biblioteca de autenticação simples e elegante para node.js. |
| Passport-Facebook | Entre no plug-in do Facebook. |
| passaporte-github2 | Entre no plug-in do GitHub. |
| Passport-Google-OAuth | Entre no Google Plugin. |
| Passport-Linkedin-OAuth2 | Entrar no plug-in do LinkedIn. |
| passaporte local | Entrar no nome de usuário e no plug-in de senha. |
| PASSAPORTE-OAUTH | Permite configurar suas próprias estratégias OAuth 1.0A e OAuth 2.0. |
| passaporte-outh2-refresh | Uma biblioteca para atualizar os tokens de acesso OAuth 2.0 usando tokens de atualização. |
| passaporte-snapchat | Entre no plug-in do Snapchat. |
| Passport-Steam-Openid | OpenID 2.0 Plugin de vapor. |
| package patch | Corrija os módulos de nós quebrados à frente das correções dos mantenedores. |
| PayPal-Rest-SDK | Biblioteca PayPal APIs. |
| pug | MOTOR MOTOR PARA EXPRESSO. |
| Sass | Compilador SASS para gerar CSS com superpotências |
| Sinon | Teste espiões, stubs e zombares para JavaScript. |
| listra | Biblioteca de API de Stripe Offical. |
| Supertest | Biblioteca de afirmação HTTP. |
| Twilio | Twilio API Library. |
| Twitch-Passport | Entre no plug-in Twitch. |
| Validador | Uma biblioteca de validadores de string e desinfetantes. |
filesize(265318); // "265.32 kB" .var token = _.find(req.user.tokens, { kind: 'twitter' }); , onde o 1º parâmetro é uma matriz e um segundo parâmetro é um objeto a ser pesquisado. 403 Error: Forbidden ao enviar um formulário?Você precisa adicionar o seguinte elemento de entrada oculto ao seu formulário. Isso foi adicionado na solicitação de tração nº 40 como parte da proteção do CSRF.
input(type='hidden', name='_csrf', value=_csrf)
NOTA: Agora é possível a lista de permissões de certos URLs. Em outras palavras, você pode especificar uma lista de rotas que devem ignorar a verificação de verificação do CSRF.
NOTA 2: Para os URLs dinâmicos da lista de permissões, use testes de expressão regular dentro do middleware do CSRF para ver se req.originalUrl corresponde ao padrão desejado.
Essa é uma mensagem de erro personalizada definida no app.js para indicar que havia um problema em conectar -se ao MongoDB:
mongoose . connection . on ( 'error' , ( err ) => {
console . error ( err ) ;
console . log ( '%s MongoDB connection error. Please make sure MongoDB is running.' , chalk . red ( '✗' ) ) ;
process . exit ( ) ;
} ) ; Você precisa ter um servidor MongoDB em execução antes de iniciar app.js Você pode baixar o MongoDB aqui ou instalá -lo através de um gerenciador de pacotes. Usuários do Windows, leia o Install MongoDB no Windows.
Dica: se você estiver sempre conectado à Internet, poderá usar o MongoDB Atlas em vez de baixar e instalar o MongoDB localmente. Você só precisará atualizar as credenciais do banco de dados no arquivo .env .
Provavelmente, você não mudou o URI do banco de dados em .env . Se MONGODB estiver definido como localhost , ele funcionará apenas em sua máquina enquanto o MongoDB estiver em execução. Quando você implanta para renderizar, OpenShift ou algum outro provedor, você não terá o MongoDB executando no localhost . Você precisa criar uma conta com o MongoDB Atlas e criar um banco de dados de camada gratuito. Consulte a implantação para obter mais informações sobre como configurar uma conta e um novo banco de dados passo a passo com o MongoDB Atlas.
Por uma questão de simplicidade. Embora possa haver uma abordagem melhor, como passar o contexto app para cada controlador, conforme descrito neste blog, acho esse estilo tão confuso para iniciantes. Levei muito tempo para entender o conceito de exports e module.exports , muito menos ter uma referência app global em outros arquivos. Para mim é um pensamento atrasado. O app.js é o "coração do aplicativo", deve ser o único referenciando modelos, rotas, controladores etc. Ao trabalhar solo em pequenos projetos, prefiro ter tudo dentro do app.js como é o caso deste servidor de API REST.
Esta seção destina -se a fornecer uma explicação detalhada de como uma funcionalidade específica funciona. Talvez você esteja apenas curioso sobre como isso funciona, ou talvez esteja perdido e confuso ao ler o código, espero que isso forneça algumas orientações para você.
O HTML5 UP possui muitos modelos bonitos que você pode baixar gratuitamente.
Ao baixar o arquivo zip, ele vem com index.html , imagens , pastas CSS e JS . Então, como você o integra com o iniciante do Hackathon? O Hackathon Starter usa a estrutura do Bootstrap CSS, mas esses modelos não. Tentar usar os dois arquivos CSS ao mesmo tempo provavelmente resultará em efeitos indesejados.
Nota: Usando a abordagem de modelos personalizados, você deve entender que não pode reutilizar nenhuma das visualizações que criei: layout, a página inicial, navegador da API, login, inscrição, gerenciamento de contas, contato. Essas visualizações foram construídas usando grade e estilos de bootstrap. Você precisará atualizar manualmente a grade usando uma sintaxe diferente fornecida no modelo. Dito isto, você pode misturar e combinar se quiser fazer isso: use Bootstrap para a interface do aplicativo principal e um modelo personalizado para uma página de destino.
Vamos começar do início. Para este exemplo, usarei o modelo de velocidade de escape:
NOTA: Por uma questão de simplicidade, considerarei apenas index.html e pular left-sidebar.html , no-sidebar.html , right-sidebar.html .
Mova todos os arquivos JavaScript de html5up-escape-velocity/js para public/js . Em seguida, mova todos os arquivos CSS de html5up-escape-velocity/css para public/css . E, finalmente, mova todas as imagens de html5up-escape-velocity/images para o public/images . Você pode movê -lo para a pasta IMG existente, mas isso exigiria alterar manualmente todas as referências img . Pegue o conteúdo do index.html e cole -o em html em pug.
Nota: Não se esqueça de atualizar todos os caminhos CSS e JS de acordo.
Crie um novo arquivo escape-velocity.pug views Sempre que você vir o código res.render('account/login') - isso significa que ele pesquisará o arquivo views/account/login.pug .
Vamos ver como fica. Crie um novo controlador Escapevelocity Inside controllers/home.js :
exports . escapeVelocity = ( req , res ) => {
res . render ( 'escape-velocity' , {
title : 'Landing Page'
} ) ;
} ; E depois crie uma rota no app.js Eu o coloquei logo após o controlador de índice:
app . get ( '/escape-velocity' , homeController . escapeVelocity ) ; Reinicie o servidor (se você não estiver usando o Nodemon ); Então você deve ver o novo modelo em http://localhost:8080/escape-velocity
Vou parar aqui, mas se você quiser usar esse modelo como mais do que apenas uma página, dê uma olhada em como esses modelos de pug funcionam: layout.pug - modelo base, index.pug - página inicial, partials/header.pug - bootstrap Navbar, partials/footer.pug - Footer. Você terá que separá -lo manualmente em pedaços menores. Descubra qual parte do modelo você deseja manter o mesmo em todas as páginas - esse é o seu novo layout.pug . Em seguida, cada página que muda, seja index.pug , about.pug , contact.pug será incorporada no seu novo layout.pug via block content . Use modelos existentes como referência.
Este é um processo bastante demorado, e os modelos que você obtém de outros lugares podem ter mais um sistema de grade. É por isso que escolhi o Bootstrap para o iniciante do Hackathon. Muitas pessoas já estão familiarizadas com o Bootstrap , além de ser fácil começar com ele se você nunca usou Bootstrap . Você também pode comprar muitos temas de bootstrap lindamente projetados no Themeforest e usá-los como substituto para iniciantes de hackathon. No entanto, se você deseja ir com um design HTML/CSS completamente personalizado, isso deve ajudá -lo a começar!
As mensagens flash permitem exibir uma mensagem no final da solicitação e acessá -la na próxima solicitação e apenas a próxima solicitação. Por exemplo, em uma tentativa de login com falha, você exibiria um alerta com alguma mensagem de erro, mas assim que atualizará essa página ou visitaria uma página diferente e voltará à página de login, essa mensagem de erro será desaparecida. É exibido apenas uma vez. Este projeto usa o módulo Express-Flash para mensagens flash. E esse módulo é construído sobre o Connect-Flash , que é o que eu usei neste projeto inicialmente. Com o Express-Flash, você não precisa enviar uma mensagem flash explicitamente para todas as visualizações dentro de res.render() . Todas as mensagens flash estão disponíveis em suas visualizações via objeto de messages por padrão, graças ao Express-Flash .
As mensagens flash têm um processo de duas etapas. Você usa req.flash('errors', { msg: 'Error messages goes here' } para criar uma mensagem flash em seus controladores e depois exibi -las em suas visualizações:
if messages . errors
.alert.alert-danger.fade.in
for error in messages . errors
div = error . msg Na primeira etapa, 'errors' é o nome de uma mensagem flash, que deve corresponder ao nome do objeto da propriedade no objeto messages em suas opiniões. Você coloca as mensagens alertas dentro if message.errors porque não deseja mostrar que as mensagens flash estão presentes. A razão pela qual você passa um erro como { msg: 'Error message goes here' } em vez de apenas uma string - 'Error message goes here' , é por uma questão de consistência. Para esclarecer isso, o módulo de validador expresso que é usado para validar e higienizar a entrada do usuário, retorna todos os erros como uma matriz de objetos, onde cada objeto tem uma propriedade msg com uma mensagem por que ocorreu um erro. Aqui está um exemplo mais geral do que o Validador Expresso retorna quando há erros presentes:
[
{ param : "name" , msg : "Name is required" , value : "<received input>" } ,
{ param : "email" , msg : "A valid email is required" , value : "<received input>" }
] Para manter -se consistente com esse estilo, você deve passar todas as mensagens flash como { msg: 'My flash message' } em vez de uma string. Caso contrário, você verá uma caixa de alerta sem uma mensagem de erro. Isso ocorre porque, no modelo parcials/flash.pug, ele tentará emitir error.msg (ou seja, "My flash message".msg ); em outras palavras, tentará chamar um método msg em um objeto String , que retornará indefinido . Tudo o que acabei de mencionar sobre erros, também se aplica a mensagens "Informações" e "Sucesso", e você pode até criar um novo, como:
Controlador de uso de dados (exemplo)
req.flash('warning', { msg: 'You have exceeded 90% of your data usage' });
Página da conta de usuário (exemplo)
if messages . warning
.alert.alert-warning.fade.in
for warning in messages . warning
div = warning . msg partials/flash.pug é um modelo parcial que contém como as mensagens flash são formatadas. Anteriormente, as mensagens flash estavam espalhadas por cada visualização que usavam mensagens flash (contato, login, inscrição, perfil), mas agora, felizmente, ele usa uma abordagem seca .
O modelo parcial das mensagens flash está incluído no layout.pug , junto com rodapé e navegação.
body
include partials/header
.container
include partials/flash
block content
include partials/footerSe você tiver mais alguma dúvida sobre mensagens flash, sinta-se à vontade para abrir um problema e atualizarei esse mini-guide de acordo ou enviará uma solicitação de tração se quiser incluir algo que eu perdi.
Uma maneira mais correta de dizer que isso seria "Como faço para criar uma nova rota?" The main file app.js contains all the routes. Each route has a callback function associated with it. Sometimes you will see three or more arguments for a route. In a case like that, the first argument is still a URL string, while middle arguments are what's called middleware. Think of middleware as a door. If this door prevents you from continuing forward, you won't get to your callback function. One such example is a route that requires authentication.
app . get ( '/account' , passportConfig . isAuthenticated , userController . getAccount ) ; It always goes from left to right. A user visits /account page. Then isAuthenticated middleware checks if you are authenticated:
exports . isAuthenticated = ( req , res , next ) => {
if ( req . isAuthenticated ( ) ) {
return next ( ) ;
}
res . redirect ( '/login' ) ;
} ; If you are authenticated, you let this visitor pass through your "door" by calling return next(); . It then proceeds to the next middleware until it reaches the last argument, which is a callback function that typically renders a template on GET requests or redirects on POST requests. In this case, if you are authenticated, you will be redirected to the Account Management page; otherwise, you will be redirected to the Login page.
exports . getAccount = ( req , res ) => {
res . render ( 'account/profile' , {
title : 'Account Management'
} ) ;
} ; Express.js has app.get , app.post , app.put , app.delete , but for the most part, you will only use the first two HTTP verbs, unless you are building a RESTful API. If you just want to display a page, then use GET , if you are submitting a form, sending a file then use POST .
Here is a typical workflow for adding new routes to your application. Let's say we are building a page that lists all books from the database.
Step 1. Start by defining a route.
app . get ( '/books' , bookController . getBooks ) ;Note: As of Express 4.x you can define your routes like so:
app . route ( '/books' )
. get ( bookController . getBooks )
. post ( bookController . createBooks )
. put ( bookController . updateBooks )
. delete ( bookController . deleteBooks )And here is how a route would look if it required an authentication and an authorization middleware:
app . route ( '/api/twitter' )
. all ( passportConfig . isAuthenticated )
. all ( passportConfig . isAuthorized )
. get ( apiController . getTwitter )
. post ( apiController . postTwitter ) Use whichever style makes sense to you. Either one is acceptable. I think that chaining HTTP verbs on app.route is a very clean and elegant approach, but on the other hand, I can no longer see all my routes at a glance when you have one route per line.
Step 2. Create a new schema and a model Book.js inside the models directory.
const mongoose = require ( 'mongoose' ) ;
const bookSchema = new mongoose . Schema ( {
name : String
} ) ;
const Book = mongoose . model ( 'Book' , bookSchema ) ;
module . exports = Book ; Step 3. Create a new controller file called book.js inside the controllers directory.
/**
* GET /books
* List all books.
*/
const Book = require ( '../models/Book.js' ) ;
exports . getBooks = ( req , res ) => {
Book . find ( ( err , docs ) => {
res . render ( 'books' , { books : docs } ) ;
} ) ;
} ; Step 4. Import that controller in app.js .
const bookController = require ( './controllers/book' ) ; Step 5. Create books.pug template.
extends layout
block content
.page-header
h3 All Books
ul
for book in books
li = book . nameÉ isso! I will say that you could have combined Step 1, 2, 3 as following:
app . get ( '/books' , ( req , res ) => {
Book . find ( ( err , docs ) => {
res . render ( 'books' , { books : docs } ) ;
} ) ;
} ) ; Sure, it's simpler, but as soon as you pass 1000 lines of code in app.js it becomes a little challenging to navigate the file. I mean, the whole point of this boilerplate project was to separate concerns, so you could work with your teammates without running into MERGE CONFLICTS . Imagine you have four developers working on a single app.js , I promise you it won't be fun resolving merge conflicts all the time. If you are the only developer, then it's okay. But as I said, once it gets up to a certain LoC size, it becomes difficult to maintain everything in a single file.
That's all there is to it. Express.js is super simple to use. Most of the time you will be dealing with other APIs to do the real work: Mongoose for querying database, socket.io for sending and receiving messages over WebSockets, sending emails via Nodemailer, form validation using validator.js library, parsing websites using Cheerio, etc.
Dan Stroot submitted an excellent pull request that adds a real-time dashboard with socket.io. And as much as I'd like to add it to the project, I think it violates one of the main principles of the Hackathon Starter:
When I started this project, my primary focus was on simplicity and ease of use. I also tried to make it as generic and reusable as possible to cover most use cases of hackathon web apps, without being too specific .
When I need to use socket.io, I really need it, but most of the time - I don't. But more importantly, WebSockets support is still experimental on most hosting providers. Due to past provider issues with WebSockets, I have not include socket.io as part of the Hackathon Starter. For now... If you need to use socket.io in your app, please continue reading.
First, you need to install socket.io:
npm install socket . io Replace const app = express(); com o seguinte código:
const app = express ( ) ;
const server = require ( 'http' ) . Server ( app ) ;
const io = require ( 'socket.io' ) ( server ) ; I like to have the following code organization in app.js (from top to bottom): module dependencies, import controllers, import configs, connect to database, express configuration, routes, start the server, socket.io stuff. That way I always know where to look for things.
Add the following code at the end of app.js :
io . on ( 'connection' , ( socket ) => {
socket . emit ( 'greet' , { hello : 'Hey there browser!' } ) ;
socket . on ( 'respond' , ( data ) => {
console . log ( data ) ;
} ) ;
socket . on ( 'disconnect' , ( ) => {
console . log ( 'Socket disconnected' ) ;
} ) ;
} ) ;One last thing left to change:
app . listen ( app . get ( 'port' ) , ( ) => {para
server . listen ( app . get ( 'port' ) , ( ) => {At this point, we are done with the back-end.
You now have a choice - to include your JavaScript code in Pug templates or have all your client-side JavaScript in a separate file - in app.js . I admit, when I first started with Node.js and JavaScript in general, I placed all JavaScript code inside templates because I have access to template variables passed in from Express right then and there. It's the easiest thing you can do, but also the least efficient and harder to maintain. Since then I almost never include inline JavaScript inside templates anymore.
But it's also understandable if you want to take the easier road. Most of the time you don't even care about performance during hackathons, you just want to "get shit done" before the time runs out. Well, either way, use whichever approach makes more sense to you. At the end of the day, it's what you build that matters, not how you build it.
If you want to stick all your JavaScript inside templates, then in layout.pug - your main template file, add this to head block.
script ( src = '/socket.io/socket.io.js' )
script .
let socket = io . connect ( window . location . href );
socket . on ( ' greet ' , function ( data ) {
console . log (data);
socket . emit ( ' respond ' , { message : ' Hey there, server! ' });
}); Note: Notice the path of the socket.io.js , you don't actually have to have socket.io.js file anywhere in your project; it will be generated automatically at runtime.
If you want to have JavaScript code separate from templates, move that inline script code into app.js , inside the $(document).ready() function:
$ ( document ) . ready ( function ( ) {
// Place JavaScript code here...
let socket = io . connect ( window . location . href ) ;
socket . on ( 'greet' , function ( data ) {
console . log ( data ) ;
socket . emit ( 'respond' , { message : 'Hey there, server!' } ) ;
} ) ;
} ) ;And we are done!
Declares a read-only named constant.
const name = 'yourName' ;Declares a block scope local variable.
let index = 0 ; Using the `${}` syntax, strings can embed expressions.
const name = 'Oggy' ;
const age = 3 ;
console . log ( `My cat is named ${ name } and is ${ age } years old.` ) ; To import functions, objects, or primitives exported from an external module. These are the most common types of importing.
const name = require ( 'module-name' ) ; const { foo , bar } = require ( 'module-name' ) ;To export functions, objects, or primitives from a given file or module.
module . exports = { myFunction } ; module . exports . name = 'yourName' ; module . exports = myFunctionOrClass ; The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.
myFunction ( ... iterableObject ) ; < ChildComponent { ... this . props } /> A Promise is used in asynchronous computations to represent an operation that hasn't completed yet but is expected in the future.
var p = new Promise ( function ( resolve , reject ) { } ) ; The catch() method returns a Promise and deals with rejected cases only.
p . catch ( function ( reason ) { /* handle rejection */ } ) ; The then() method returns a Promise. It takes two arguments: callback for the success & failure cases.
p . then ( function ( value ) { /* handle fulfillment */ } , function ( reason ) { /* handle rejection */ } ) ; The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved or rejects with the reason of the first passed promise that rejects.
Promise . all ( [ p1 , p2 , p3 ] ) . then ( function ( values ) { console . log ( values ) } ) ; Arrow function expression. Shorter syntax & lexically binds the this value. Arrow functions are anonymous.
singleParam => { statements } ( ) => { statements } ( param1 , param2 ) => expression const arr = [ 1 , 2 , 3 , 4 , 5 ] ;
const squares = arr . map ( x => x * x ) ; The class declaration creates a new class using prototype-based inheritance.
class Person {
constructor ( name , age , gender ) {
this . name = name ;
this . age = age ;
this . gender = gender ;
}
incrementAge ( ) {
this . age ++ ;
}
}? Credits : DuckDuckGo and @DrkSephy.
? back to top
Math . floor ( Date . now ( ) / 1000 ) ; moment().unix();
var now = new Date ( ) ;
now . setMinutes ( now . getMinutes ( ) + 30 ) ; moment().add(30, 'minutes');
// DD-MM-YYYY
var now = new Date ( ) ;
var DD = now . getDate ( ) ;
var MM = now . getMonth ( ) + 1 ;
var YYYY = now . getFullYear ( ) ;
if ( DD < 10 ) {
DD = '0' + DD ;
}
if ( MM < 10 ) {
MM = '0' + MM ;
}
console . log ( MM + '-' + DD + '-' + YYYY ) ; // 03-30-2016 console.log(moment(new Date(), 'MM-DD-YYYY'));
// hh:mm (12 hour time with am/pm)
var now = new Date ( ) ;
var hours = now . getHours ( ) ;
var minutes = now . getMinutes ( ) ;
var amPm = hours >= 12 ? 'pm' : 'am' ;
hours = hours % 12 ;
hours = hours ? hours : 12 ;
minutes = minutes < 10 ? '0' + minutes : minutes ;
console . log ( hours + ':' + minutes + ' ' + amPm ) ; // 1:43 am console.log(moment(new Date(), 'hh:mm A'));
var today = new Date ( ) ;
var nextWeek = new Date ( today . getTime ( ) + 7 * 24 * 60 * 60 * 1000 ) ; moment().add(7, 'days');
var today = new Date ( ) ;
var yesterday = date . setDate ( date . getDate ( ) - 1 ) ; moment().add(-1, 'days');
? back to top
User . find ( ( err , users ) => {
console . log ( users ) ;
} ) ; let userEmail = '[email protected]' ;
User . findOne ( { email : userEmail } , ( err , user ) => {
console . log ( user ) ;
} ) ; User
. find ( )
. sort ( { _id : - 1 } )
. limit ( 5 )
. exec ( ( err , users ) => {
console . log ( users ) ;
} ) ; Let's suppose that each user has a votes field and you would like to count the total number of votes in your database across all users. One very inefficient way would be to loop through each document and manually accumulate the count. Or you could use MongoDB Aggregation Framework instead:
User . aggregate ( { $group : { _id : null , total : { $sum : '$votes' } } } , ( err , votesCount ) => {
console . log ( votesCount . total ) ;
} ) ;? back to top
You will need to install docker and docker-compose on your system. If you are using WSL, you will need to install Docker Desktop on Windows and docker-compose on WSL.
Docker installation
Common problems setting up docker
After installing docker, start the application with the following commands :
# To build the project while supressing most of the build messages
docker-compose build web
# To build the project without supressing the build messages or using cached data
docker-compose build --no-cache --progress=plain web
# To start the application (or to restart after making changes to the source code)
docker-compose up web
To view the app, find your docker IP address + port 8080 ( this will typically be http://localhost:8080/ ). To use a port other than 8080, you would need to modify the port in app.js, Dockerfile, and docker-compose.yml.
Once you are ready to deploy your app, you will need to create an account with a cloud platform to host it. These are not the only choices, but they are my top picks. Additionally, you can create an account with MongoDB Atlas and then pick one of the providers below. Again, there are plenty of other choices, and you are not limited to just the ones listed below.
Render provides free nodejs hosting for repos on Github and Gitlab.
0.0.0.0/0 . Click SAVE to save the 0.0.0.0/0 whitelist..env.example with this URI string. Make sure to replace the with the db User password that you created under the Security tab.We are deploying your changes . You will need to wait for the deployment to finish before using the DB in your application.sudo gem install rhc ?rhc login and enter your OpenShift credentialsrhc app create MyApp nodejs-0.10git remote add openshift YOUR_GIT_REMOTE Add these two lines to app.js , just place them anywhere before app.listen() :
var IP_ADDRESS = process . env . OPENSHIFT_NODEJS_IP || '127.0.0.1' ;
var PORT = process . env . OPENSHIFT_NODEJS_PORT || 8080 ; Then change app.listen() to:
app . listen ( PORT , IP_ADDRESS , ( ) => {
console . log ( `Express server listening on port ${ PORT } in ${ app . settings . env } mode` ) ;
} ) ; Add this to package.json , after name and version . This is necessary because, by default, OpenShift looks for server.js file. And by specifying supervisor app.js it will automatically restart the server when node.js process crashes.
"main" : "app.js" ,
"scripts" : {
"start" : "supervisor app.js"
} ,git push -f openshift master-f (force) flag because OpenShift creates a dummy server with the welcome page when you create a new Node.js app. Passing -f flag will override everything with your Hackathon Starter project repository. Do not run git pull as it will create unnecessary merge conflicts.git remote add azure [Azure Git URL]git push azure masterNOTE At this point it appears that Bluemix's free tier to host NodeJS apps is limited to 30 days. If you are looking for a free tier service to host your app, Render might be a better choice at this point
Create a Bluemix Account
Sign up for Bluemix, or use an existing account.
Download and install the Cloud Foundry CLI to push your applications to Bluemix.
Create a manifest.yml file in the root of your application.
applications:
- name: <your-app-name>
host: <your-app-host>
memory: 128M
services:
- myMongo-db-name
The host you use will determinate your application URL initially, eg <host>.mybluemix.net . The service name 'myMongo-db-name' is a declaration of your MongoDB service. If you are using other services like Watson for example, then you would declare them the same way.
$ cf login -a https://api.ng.bluemix.net
$ cf create-service mongodb 100 [your-service-name]
Note: this is a free and experiment verion of MongoDB instance. Use the MongoDB by Compose instance for production applications:
$ cf create-service compose-for-mongodb Standard [your-service-name]'
Push the application
$ cf push
$ cf env <your-app-name >
(To view the *environment variables* created for your application)
Done , now go to the staging domain ( <host>.mybluemix.net ) and see your app running.
Be sure to check out the full list of Watson services to forwarder enhance your application functionality with a little effort. Watson services are easy to get going; it is simply a RESTful API call. Here is an example of a Watson Toner Analyzer to understand the emotional context of a piece of text that you send to Watson.
Virtual Assistant - Deliver consistent and intelligent customer care across all channels and touchpoints with conversational AI.
Natural Language Understanding - Analyze text to extract meta-data from content such as concepts, entities, keywords and more.
Discovery - Accelerate business decisions and processes with an AI-powered intelligent document understanding and content analysis platform.
Orchestrate - Hand off tedious tasks to Watson and never work the same way again.
List of Watson Services.
Download and install Node.js
Select or create a Google Cloud Platform Console project
Enable billing for your project (there's a $300 free trial)
Install and initialize the Google Cloud SDK
Create an app.yaml file at the root of your hackathon-starter folder with the following contents:
runtime : nodejs
env : flex
manual_scaling :
instances : 1 Make sure you've set MONGODB_URI in .env.example
Run the following command to deploy the hackathon-starter app:
gcloud app deployMonitor your deployed app in the Cloud Console
View the logs for your app in the Cloud Console
If you are starting with this boilerplate to build an application for prod deployment, or if after your hackathon you would like to get your project hardened for production use, see prod-checklist.md.
You can find the changelog for the project in: CHANGELOG.md
If something is unclear, confusing, or needs to be refactored, please let me know. Pull requests are always welcome, but due to the opinionated nature of this project, I cannot accept every pull request. Please open an issue before submitting a pull request. This project uses Airbnb JavaScript Style Guide with a few minor exceptions. If you are submitting a pull request that involves Pug templates, please make sure you are using spaces , not tabs.
The MIT License (MIT)
Copyright (c) 2014-2023 Sahat Yalkabov
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.