Today we are going to develop a simple News app with the help of NodeJS , Express , EJS and bootstrap.
There are going to be 2 main features in this website search and display news articles And we are going to use Newapi for getting news articles.
Lets Start
Initialize the New Project
To initialize the new project you just need to create a new folder "News App" and open folder in visual studio code or any other IDE and run the below code in command line
npm init
This takes only few seconds and also asks few question about your project like project name , description etc. after that initialization is over and a file name "Package.json" is generated .
Structure of project
As with the reference of the above image create folders and files leave node_modules package-lock and package-json as they generate automatically .
Install Dependencies
These are the Dependencies we need to install for our project.
express
ejs
body-parser
axios
math
moment
For installing these Dependencies you just need to write the below code in your terminal
npm install express ejs body-parser axios math moment
Setup App for run
To start the server automatically we just need to install Nodemon which restart server automatically when any change is detected
npm install -D nodemon
Setup application for developer run and normal run. Just change the Script section with the below code in package.json
.
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
Start developer local server
To start our app for testing/developer just simply type the following command in the command line:
npm run dev
Application
Lets code our app.js
file this is the main file and it will sit in the root of our website.
In this file we have to setup our server .
file:-> app.js
const express = require('express')
const app=express()
const port = process.env.PORT||3000;
const bodyParser = require('body-parser');
const moment = require('moment')
app.locals.moment = moment;
// template engine
app.use(express.static('public'))
app.set('view engine','ejs')
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/',require('./routes/news'))
app.set('views','./views')
app.listen(port,()=> console.log("started"))
Routes
Lets build a extremal routes
External routing is a way of structuring your code so that it stays nice and organized by taking the route implementations outside of the main server file and moving them into a separate router file.
First you need your NewsApi API key for getting data , Go to NewsApi site and get your Api key then and simply replace YOUR_API
in the url with your Api key in the below code
file:-> routes/news.js
const express = require('express')
const axios = require('axios')
const newsr=express.Router()
const moment = require('moment')
const math = require('math')
newsr.get('/',async(req,res)=>{
try {
var url = 'http://newsapi.org/v2/top-headlines?' +
'country=in&' +
'apiKey={YOUR_API}';
const news_get =await axios.get(url)
res.render('news',{articles:news_get.data.articles})
} catch (error) {
if(error.response){
console.log(error)
}
}
})
newsr.post('/search',async(req,res)=>{
const search=req.body.search
// console.log(req.body.search)
try {
var url = `http://newsapi.org/v2/everything?q=${search}&apiKey={YOUR_API}`
const news_get =await axios.get(url)
res.render('news',{articles:news_get.data.articles})
} catch (error) {
if(error.response){
console.log(error)
}
}
})
module.exports=newsr
Views
file:-> views/news.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>News</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=PT+Sans:ital@1&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<style>
.form-control{
border-color: red;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light navbar-fixed-top fixed-top">
<a class="navbar-brand" href="/" style="font-weight: 700;
font-size: 24px;"> <span style="color: red;" >X</span>-news</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse searc-bar" id="navbarSupportedContent">
<form class="form-inline my-2 my-lg-0" action="/search" method="POST">
<input class="form-control mr-sm-2" name="search" type="search" placeholder="Search" style="width: 522px;"
aria-label="Search">
<button class="btn btn-outline-danger my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="news-container ">
<div class="news ">
<% articles.forEach(function(article,index){ %>
<% if ((typeof article.url=='object') || (typeof article.title=='object') || (typeof article.urlToImage=='object') || (typeof article.content=='object')){ %>
<% } else{ %>
<a href="<%- article.url %>" target="_blank" class="news-box Hover-effect">
<img src="<%- article.urlToImage %>" alt="Image">
<h3>
<%- article.title %>
</h3>
<p>
<%- article.content.replace(/<[^>]+>/g, '') %>
</p>
<br>
<p style="margin-bottom: 0px; position: absolute; right: 0; bottom: 0; font-family: ui-monospace;">Updated: <span style="color:red;" ><%- new Date(article.publishedAt.slice(0,10)).toDateString() %> <%- moment.utc(article.publishedAt).local().format('hh : mm A') %> </span></p>
</a>
<% } %>
<% }) %>
</div>
</div>
<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
Style
body{
margin: 0;
font-family: sans-serif;
background-color: rgba(245, 238, 238, 0.89);
}
nav{
margin-bottom: 40px;
}
img{
max-width: 100%;
transition: all 0.7s ;
}
.Hover-effect:hover{
transform: translateY(-3px) scale(1.01);
}
.Hover-effect:hover img{
transform: translateY(-5px) scale(1.02);
box-shadow: 10px 9px 17px -10px rgba(0,0,0,0.28);
}
h3{
font-size: 1.55rem;
}
h2{
font-size: 1.55rem;
}
.news-container{
margin-bottom: 69px;
padding: 0 1rem;
padding-top: 92px;
}
.news{
display: grid;
grid-template-columns: repeat(auto-fill,minmax(300px,1fr));
grid-gap: 2rem;
}
.news-box{
transition: all 0.3s ;
text-decoration: none;
color: rgb(29, 25, 25);
background-color: white;
padding: 20px;
}
.news-box:hover{
text-decoration: none;
color: rgb(29, 25, 25);;
box-shadow: 0 3px 3px rgba(0,0,0,0.16), 0 3px 3px rgba(0,0,0,0.23);
}
.searc-bar{
justify-content: center;
}
/* #effect ********************** */
.Hover-effect {
position: relative;
}
:root{
--underline_color: red;
--underline-hight:0.175rem;
}
.Hover-effect::after {
content: "";
position: absolute;
width: 100%;
height: var(--underline-hight);
background-color: var(--underline_color);
left: 0;
bottom: 0;
transform: scale(0, 1);
transition: transform 0.3s ease;
}
.Hover-effect:hover::after {
transform: scale(1, 1);
}
Top comments (11)
Cool article ! thanks
One or two things :
(For me) the tag 'article.content' (in news view) seems to return some tags (ul li) that breaks the design.
You should add some details for the different steps. For exemple : once the step "Application" written, the server throw an error... because the next step is not written yet. It's important if we don't want to search and waste times :)
cheers
Issue resolved by just replacing 'article.content' to 'articel.content.replace(/<[^>]+>/g, '') '
Thanks for informing😊
Good one!
However there is no need to install body-parser as express.js include it. use instead
Thanks for the suggestion bro.
thanks man for providing this amazing information. I have used a NewsData.io NewsAPI to integrate news data with my website. can you tell me more about this API??
Neat! Thanks! :)
I noticed you put your actual API key in the example rather than the template text "YOUR_API" you mentioned.
Thanks for informing bro🙌
thanks bro
Hi Man, You are Super cool for sharing this. We are truly thankful!
Cool article and project!
Join me at #CCDaysOnline to attend exciting sessions on Serverless & DevOps on 24 & 25 March 2021. For registration and event details: t.co/z6oTSV1qgq