├── .env.template ├── .gitignore ├── Dockerfile ├── README.md ├── app.js ├── bin └── www ├── client ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.ts │ ├── followers.component.css │ ├── followers.component.html │ ├── followers.component.ts │ ├── main.ts │ ├── rxjs-operators.ts │ ├── tweet.ts │ ├── tweets.component.css │ ├── tweets.component.html │ ├── tweets.component.ts │ ├── twitter-dates.pipe.spec.ts │ ├── twitter-dates.pipe.ts │ ├── twitter.service.spec.ts │ ├── twitter.service.ts │ └── user.ts ├── index.html ├── package.json ├── styles.css ├── systemjs.config.js ├── tsconfig.json ├── typings.json ├── typings │ ├── browser.d.ts │ ├── browser │ │ └── ambient │ │ │ ├── es6-shim │ │ │ └── index.d.ts │ │ │ ├── jasmine │ │ │ └── index.d.ts │ │ │ └── node │ │ │ └── index.d.ts │ ├── main.d.ts │ └── main │ │ └── ambient │ │ ├── es6-shim │ │ └── index.d.ts │ │ ├── jasmine │ │ └── index.d.ts │ │ └── node │ │ └── index.d.ts └── unit-tests.html ├── npm-debug.log ├── package.json └── routes └── index.js /.env.template: -------------------------------------------------------------------------------- 1 | # Fill in your Twitter API keys and copy to .env 2 | 3 | TWITTER_CONSUMER_KEY= 4 | TWITTER_CONSUMER_SECRET= 5 | TWITTER_ACCESS_TOKEN_KEY= 6 | TWITTER_ACCESS_TOKEN_SECRET= 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | client/node_modules 4 | client/app/*.js 5 | client/app/*.js.map 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:argon 2 | 3 | # Create app directory 4 | RUN mkdir -p /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | # Install app dependencies 8 | COPY package.json /usr/src/app/ 9 | RUN npm install 10 | 11 | # Bundle app source 12 | COPY . /usr/src/app 13 | 14 | EXPOSE 8080 15 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Express_Angular2_Twitter_App 2 | 3 | an Express-Angular 2 app using the Twitter API to display Corcoran data 4 | 5 | ## Update 6 | There have been some changes to Angular 2 since the creation of this app (esp in regards to the router). 7 | I've made another starter Angular 2 Express App with a more recent version of Angular 2 here: https://github.com/bolducp/angular2-express-app-starter 8 | 9 | ### View App 10 | Deployed via Heroku here: https://young-meadow-25237.herokuapp.com/ 11 | 12 | ### Usage 13 | 14 | 1: clone the repo 15 | 16 | 2: `npm install` in outer directory & inner Client directory 17 | 18 | 3: get developer API keys from Twitter 19 | 20 | 4: fillout the .env.template and copy it as ".env". It should include the following keys: 21 | ``` 22 | TWITTER_CONSUMER_KEY=your_key_here 23 | TWITTER_CONSUMER_SECRET=your_key_here 24 | TWITTER_ACCESS_TOKEN_KEY=your_key_here 25 | TWITTER_ACCESS_TOKEN_SECRET=your_key_here 26 | ``` 27 | 28 | 5: cd into the Client directory and run `tsc` to compile the Typescript 29 | 30 | 6: run `npm start` or `nodemon` from the terminal, and navigate to localhost:3000 in the browser 31 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var logger = require('morgan'); 4 | var cookieParser = require('cookie-parser'); 5 | var bodyParser = require('body-parser'); 6 | require('dotenv').config(); 7 | 8 | var app = express(); 9 | 10 | app.use(logger('dev')); 11 | app.use(bodyParser.json()); 12 | app.use(bodyParser.urlencoded({ extended: false })); 13 | app.use(cookieParser()); 14 | app.use(express.static(path.join(__dirname, 'client'))); 15 | 16 | app.use('/', require('./routes/index')); 17 | 18 | // catch 404 and forward to error handler 19 | app.use(function(req, res, next) { 20 | var err = new Error('Not Found'); 21 | err.status = 404; 22 | next(err); 23 | }); 24 | 25 | //error handlers 26 | 27 | // development error handler 28 | // will print stacktrace 29 | if (app.get('env') === 'development') { 30 | app.use(function(err, req, res, next) { 31 | res.status(err.status || 500); 32 | res.render('error', { 33 | message: err.message, 34 | error: err 35 | }); 36 | }); 37 | } 38 | 39 | // production error handler 40 | // no stacktraces leaked to user 41 | app.use(function(err, req, res, next) { 42 | res.status(err.status || 500); 43 | res.render('error', { 44 | message: err.message, 45 | error: {} 46 | }); 47 | }); 48 | 49 | 50 | module.exports = app; 51 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('twitterFull:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '8080'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /client/app/app.component.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: black; 3 | margin-bottom: 0; 4 | } 5 | 6 | nav a { 7 | padding: 5px 10px; 8 | text-decoration: none; 9 | margin-top: 10px; 10 | display: inline-block; 11 | background-color: #eee; 12 | border-radius: 4px; 13 | } 14 | 15 | nav a:visited, a:link { 16 | color: #607D8B; 17 | } 18 | 19 | nav a:hover { 20 | color: #039be5; 21 | background-color: #CFD8DC; 22 | } 23 | 24 | nav a.router-link-active { 25 | color: #039be5; 26 | } 27 | 28 | #header { 29 | text-align: center; 30 | } 31 | -------------------------------------------------------------------------------- /client/app/app.component.html: -------------------------------------------------------------------------------- 1 |