Compare commits

..

3 Commits

Author SHA1 Message Date
Tj Holowaychuk
53589b4f37 Release 0.14.1 2010-07-05 14:24:46 -07:00
Tj Holowaychuk
aaed3e134d Style fix 2010-07-05 14:20:59 -07:00
Benny Wong
91ced24359 Newer versions of node use Buffer to hold the ejs text 2010-06-29 08:11:57 -07:00
342 changed files with 9400 additions and 26221 deletions

View File

@@ -1,11 +0,0 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[{*.js,*.json,*.yml}]
indent_size = 2
indent_style = space

View File

@@ -1,2 +0,0 @@
coverage
node_modules

View File

@@ -1,14 +0,0 @@
root: true
env:
es2022: true
node: true
rules:
eol-last: error
eqeqeq: [error, allow-null]
indent: [error, 2, { MemberExpression: "off", SwitchCase: 1 }]
no-trailing-spaces: error
no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: true }]
no-restricted-globals:
- error
- name: Buffer
message: Use `import { Buffer } from "node:buffer"` instead of the global Buffer.

View File

@@ -1,17 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
- package-ecosystem: npm
directory: /
schedule:
interval: monthly
time: "23:00"
timezone: Europe/London
open-pull-requests-limit: 10
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

View File

@@ -1,117 +0,0 @@
name: ci
on:
push:
branches:
- master
- develop
- '4.x'
- '5.x'
- '5.0'
paths-ignore:
- '*.md'
pull_request:
workflow_dispatch:
permissions:
contents: read
# Cancel in progress workflows
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
concurrency:
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm install --ignore-scripts --include=dev
- name: Run lint
run: npm run lint
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 19, 20, 21, 22, 23, 24, 25]
# Node.js release schedule: https://nodejs.org/en/about/releases/
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ matrix.node-version }}
- name: Configure npm loglevel
run: |
npm config set loglevel error
shell: bash
- name: Install dependencies
run: npm install
- name: Output Node and NPM versions
run: |
echo "Node.js version: $(node -v)"
echo "NPM version: $(npm -v)"
- name: Run tests
shell: bash
run: npm run test-ci
- name: Upload code coverage
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
path: ./coverage/lcov.info
retention-days: 1
coverage:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install lcov
shell: bash
run: sudo apt-get -y install lcov
- name: Collect coverage reports
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
path: ./coverage
pattern: coverage-node-*
- name: Merge coverage reports
shell: bash
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
- name: Upload coverage report
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
file: ./lcov.info

View File

@@ -1,74 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: ["master"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
schedule:
- cron: "0 0 * * 1"
workflow_dispatch:
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [javascript, actions]
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
with:
languages: ${{ matrix.language }}
config: |
paths-ignore:
- test
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0

View File

@@ -1,101 +0,0 @@
name: legacy
on:
push:
branches:
- master
- develop
- '4.x'
- '5.x'
- '5.0'
paths-ignore:
- '*.md'
pull_request:
paths-ignore:
- '*.md'
workflow_dispatch:
permissions:
contents: read
# Cancel in progress workflows
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
concurrency:
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [16, 17]
# Node.js release schedule: https://nodejs.org/en/about/releases/
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ matrix.node-version }}
- name: Configure npm loglevel
run: |
npm config set loglevel error
shell: bash
- name: Install dependencies
run: npm install
- name: Output Node and NPM versions
run: |
echo "Node.js version: $(node -v)"
echo "NPM version: $(npm -v)"
- name: Run tests
shell: bash
run: npm run test-ci
- name: Upload code coverage
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
path: ./coverage/lcov.info
retention-days: 1
coverage:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install lcov
shell: bash
run: sudo apt-get -y install lcov
- name: Collect coverage reports
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
path: ./coverage
pattern: coverage-node-*
- name: Merge coverage reports
shell: bash
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
- name: Upload coverage report
uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7
with:
file: ./lcov.info

View File

@@ -1,72 +0,0 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '16 21 * * 1'
push:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
with:
sarif_file: results.sarif

25
.gitignore vendored
View File

@@ -1,20 +1,7 @@
# npm
node_modules
package-lock.json
npm-shrinkwrap.json
.DS_Store
*.seed
*.log
*.gz
# Yarn
yarn-error.log
yarn.lock
# Coveralls
.nyc_output
coverage
# Benchmarking
benchmarks/graphs
# ignore additional files using core.excludesFile
# https://git-scm.com/docs/gitignore
*.csv
*.dat
*.out
benchmarks/graphs

15
.gitmodules vendored Normal file
View File

@@ -0,0 +1,15 @@
[submodule "lib/support/ext"]
path = lib/support/ext
url = git://github.com/visionmedia/ext.js.git
[submodule "lib/support/sass"]
path = lib/support/sass
url = git://github.com/visionmedia/sass.js.git
[submodule "lib/support/class"]
path = lib/support/class
url = git://github.com/visionmedia/class.js.git
[submodule "lib/support/haml"]
path = lib/support/haml
url = git://github.com/visionmedia/haml.js.git
[submodule "lib/support/multipart"]
path = lib/support/multipart
url = git://github.com/isaacs/multipart-js.git

1
.npmrc
View File

@@ -1 +0,0 @@
package-lock=false

3631
History.md

File diff suppressed because it is too large Load Diff

24
LICENSE
View File

@@ -1,24 +0,0 @@
(The MIT License)
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
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.

39
Makefile Normal file
View File

@@ -0,0 +1,39 @@
AB = ab
ABFLAGS = -n 3000 -c 50
NODE = node
COFFEE = coffee
all: test
test:
@$(NODE) spec/node.js all
app: app-chat
prof:
@$(NODE) --prof --prof_auto examples/chat/app.js
app-chat:
@$(NODE) examples/chat/app.js
app-hello-world:
@$(NODE) examples/hello-world/app.js
app-upload:
@$(NODE) examples/upload/app.js
app-coffee-upload: compile-coffee
@$(NODE) examples/coffee-upload/app.js
compile-coffee:
@$(COFFEE) examples/coffee-upload/app.coffee
benchmark: benchmarks/run
@./benchmarks/run
@./benchmarks/graph
graphs:
@./benchmarks/graph
.PHONY: install test app benchmark graphs

365
Readme.md
View File

@@ -1,278 +1,137 @@
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)
**Fast, unopinionated, minimalist web framework for [Node.js](https://nodejs.org).**
# Express
Insanely fast (and small) server-side JavaScript web development framework
built on **node.js** and the **V8 JavaScript engine**.
**This project has a [Code of Conduct].**
* Visit the [Wiki](http://wiki.github.com/visionmedia/express) for documentation
* Visit the [Google Group](http://groups.google.com/group/express-js) for discussion
Express will soon run on the [Connect](http://github.com/extjs/Connect) project, a middleware layer for nodejs.
## Table of contents
- [Table of contents](#table-of-contents)
- [Installation](#installation)
- [Features](#features)
- [Docs \& Community](#docs--community)
- [Quick Start](#quick-start)
- [Philosophy](#philosophy)
- [Examples](#examples)
- [Contributing](#contributing)
- [Security Issues](#security-issues)
- [Running Tests](#running-tests)
- [Current project team members](#current-project-team-members)
- [TC (Technical Committee)](#tc-technical-committee)
- [TC emeriti members](#tc-emeriti-members)
- [Triagers](#triagers)
- [Emeritus Triagers](#emeritus-triagers)
- [License](#license)
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
[![Linux Build][github-actions-ci-image]][github-actions-ci-url]
[![Test Coverage][coveralls-image]][coveralls-url]
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
```js
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000')
})
```
## Features (so far)
* Sexy DSL with robust sinatra-like routing
* High performance
* Session support
* Cache API
* RESTful HTTP client
* Mime helpers
* ETag support
* Redirection helpers
* Multipart file upload support
* Test helpers (mock requests etc)
* Environment based configuration
* Light-weight JavaScript class implementation via [class.js](http://github.com/visionmedia/class.js/)
* Persistent flash messages
* Route passing
* View support (ejs, haml, sass, etc)
* View partials
* View globals/helpers support
* Full test coverage
* Logger plugin with several formats
* Upload size restrictions
* Extremely readable specs
* Cookie support
## Installation
This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/).
Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
and run:
$ kiwi install express
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
Node.js 18 or higher is required.
or via npm:
If this is a brand new project, make sure to create a `package.json` first with
the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
$ npm install express
Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
or
```bash
npm install express
```
Follow [our installing guide](https://expressjs.com/en/starter/installing.html)
for more information.
## Features
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Executable for generating applications quickly
## Docs & Community
* [Website and Documentation](https://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
* [Github Discussions](https://github.com/expressjs/discussions) for discussion on the development and usage of Express
**PROTIP** Be sure to read the [migration guide to v5](https://expressjs.com/en/guide/migrating-5)
## Quick Start
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
```bash
npm install -g express-generator@4
```
Create the app:
```bash
express /tmp/foo && cd /tmp/foo
```
Install dependencies:
```bash
npm install
```
Start the server:
```bash
npm start
```
View the website at: http://localhost:3000
## Philosophy
The Express philosophy is to provide small, robust tooling for HTTP servers, making
it a great solution for single page applications, websites, hybrids, or public
HTTP APIs.
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [@ladjs/consolidate](https://github.com/ladjs/consolidate),
you can quickly craft your perfect framework.
Install via git clone:
$ git clone git://github.com/visionmedia/express.git && cd express && git submodule update --init
## Examples
To view the examples, clone the Express repository:
Below is a tiny Express application. View the [Wiki](http://wiki.github.com/visionmedia/express/) for detailed information.
```bash
git clone https://github.com/expressjs/express.git --depth 1 && cd express
```
require.paths.unshift('express/lib')
require('express')
configure(function(){
set('root', __dirname)
})
get('/user', function(){
this.redirect('/user/' + this.currentUser.id)
})
get('/user/:id', function(id){
this.render('user.haml.html', {
locals: {
user: this.currentUser,
usersOnline: Session.store.length()
}
})
})
Then install the dependencies:
run()
## Running Tests
```bash
npm install
```
Express uses the [JSpec](http://jspec.info) BDD JavaScript testing
framework to write and run elegant spec suites. JSpec is frozen
to spec/lib and **does not** require separate installation.
Then run whichever example you want:
$ make test
Run individual suites:
```bash
node examples/content-negotiation
```
$ node spec/node.js core
$ node spec/node.js mime
$ node spec/node.js routing
...
The latest release of Express is compatible with node --version:
v0.1.98
With _EDGE_ Express we do our best to keep up to date with node's _EDGE_
## More Information
## Contributing
* [JavaScript Extensions &amp; Utilities](http://github.com/visionmedia/ext.js)
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4
* [Express vs Sinatra Benchmarks](http://tjholowaychuk.com/post/543953703/express-vs-sinatra-benchmarks)
## Contributors
The Express.js project welcomes all constructive contributions. Contributions take many forms,
from code for bug fixes and enhancements, to additions and fixes to documentation, additional
tests, triaging incoming pull requests and issues, and more!
* TJ Holowaychuk (visionmedia) &lt;tj@vision-media.ca&gt;
* Aaron Heckmann (aheckmann) &lt;aaron.heckmann+github@gmail.com&gt;
* Ciaran Jessup (ciaranj) &lt;ciaranj@gmail.com&gt;
* Gareth Jones (csausdev) &lt;gareth.jones@sensis.com.au&gt;
## License
See the [Contributing Guide] for more technical details on contributing.
(The MIT License)
### Security Issues
Copyright (c) 2009 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](https://github.com/expressjs/express/security/policy).
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:
### Running Tests
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
To run the test suite, first install the dependencies:
```bash
npm install
```
Then run `npm test`:
```bash
npm test
```
## Current project team members
For information about the governance of the express.js project, see [GOVERNANCE.md](https://github.com/expressjs/discussions/blob/HEAD/docs/GOVERNANCE.md).
The original author of Express is [TJ Holowaychuk](https://github.com/tj)
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
### TC (Technical Committee)
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd**
* [LinusU](https://github.com/LinusU) - **Linus Unnebäck**
* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [crandmck](https://github.com/crandmck) - **Rand McKinney**
* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida**
<details>
<summary>TC emeriti members</summary>
#### TC emeriti members
* [dougwilson](https://github.com/dougwilson) - **Douglas Wilson**
* [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa**
* [jonathanong](https://github.com/jonathanong) - **jongleberry**
* [niftylettuce](https://github.com/niftylettuce) - **niftylettuce**
* [troygoode](https://github.com/troygoode) - **Troy Goode**
</details>
### Triagers
* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
* [bjohansebas](https://github.com/bjohansebas) - **Sebastian Beltran**
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
* [Phillip9587](https://github.com/Phillip9587) - **Phillip Barta**
* [efekrskl](https://github.com/efekrskl) - **Efe Karasakal**
* [rxmarbles](https://github.com/rxmarbles) - **Rick Markins** (he/him)
* [krzysdz](https://github.com/krzysdz)
* [GroophyLifefor](https://github.com/GroophyLifefor) - **Murat Kirazkaya**
<details>
<summary>Triagers emeriti members</summary>
#### Emeritus Triagers
* [AuggieH](https://github.com/AuggieH) - **Auggie Hudak**
* [G-Rath](https://github.com/G-Rath) - **Gareth Jones**
* [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi**
* [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi**
* [NotMoni](https://github.com/NotMoni) - **Moni**
* [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan**
* [davidmashe](https://github.com/davidmashe) - **David Ashe**
* [digitaIfabric](https://github.com/digitaIfabric) - **David**
* [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner**
* [fed135](https://github.com/fed135) - **Frederic Charette**
* [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim**
* [getspooky](https://github.com/getspooky) - **Yasser Ameur**
* [ghinks](https://github.com/ghinks) - **Glenn**
* [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed**
* [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil**
* [jake32321](https://github.com/jake32321) - **Jake Reed**
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [lekanikotun](https://github.com/lekanikotun) - **Troy Goode**
* [marsonya](https://github.com/marsonya) - **Lekan Ikotun**
* [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson**
* [maxakuru](https://github.com/maxakuru) - **Max Edell**
* [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings**
* [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav**
* [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe**
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
* [0ss](https://github.com/0ss) - **Salah**
* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
* [dpopp07](https://github.com/dpopp07) - **Dustin Popp**
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
</details>
## License
[MIT](LICENSE)
[coveralls-image]: https://img.shields.io/coverallsCoverage/github/expressjs/express?branch=master
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
[github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/expressjs/express/ci.yml?branch=master&label=ci
[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
[npm-downloads-image]: https://img.shields.io/npm/dm/express
[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
[npm-url]: https://npmjs.org/package/express
[npm-version-image]: https://img.shields.io/npm/v/express
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
[Code of Conduct]: https://github.com/expressjs/.github/blob/HEAD/CODE_OF_CONDUCT.md
[Contributing Guide]: https://github.com/expressjs/.github/blob/HEAD/CONTRIBUTING.md
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.

View File

@@ -0,0 +1,16 @@
require.paths.unshift('lib')
require('express')
require('express/plugins')
configure(function(){
//enable('cache view contents')
set('root', __dirname)
set('views', __dirname + '/../shared')
})
get('/', function(){
this.render('page.html.haml')
})
run()

View File

@@ -0,0 +1,16 @@
require.paths.unshift('lib')
require('express')
require('express/plugins')
configure(function(){
//enable('cache view contents')
set('root', __dirname)
set('views', __dirname + '/../shared')
})
get('/', function(){
this.render('style.css.sass', { layout: false })
})
run()

View File

@@ -0,0 +1,9 @@
require.paths.unshift('lib')
require('express')
get('/', function(){
return 'Hello World'
})
run()

View File

@@ -0,0 +1,15 @@
require.paths.unshift('lib')
require('express')
require('express/plugins')
configure(function(){
use(Static)
set('root', __dirname)
})
get('/', function(){
this.sendfile('benchmarks/shared/jquery.js')
})
run()

View File

@@ -0,0 +1,15 @@
require.paths.unshift('lib')
require('express')
require('express/plugins')
configure(function(){
use(Static)
set('root', __dirname)
})
get('/', function(){
this.sendfile('benchmarks/shared/huge.js')
})
run()

84
benchmarks/graph Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
COL=${COL-9}
#
# Log <msg ...>
#
# <msg ...>
#
log(){
echo "... $@"
}
#
# Output gnuplot script for line graph.
#
# <title> <node> <express> <sinatra>
#
function line() {
cat <<-EOF
set terminal png
set output "benchmarks/graphs/$1.png"
set title "$1"
set size 1,0.7
set grid y
set key left top
set xlabel "request"
set ylabel "response time (ms)"
plot "benchmarks/$2" using $COL smooth sbezier with lines title "node", \\
"benchmarks/$3" using $COL smooth sbezier with lines title "express", \\
"benchmarks/$4" using $COL smooth sbezier with lines title "sinatra thin"
EOF
}
#
# Output gnuplot script for bar graph.
#
# <title> <node> <express> <sinatra>
#
function bar() {
cat <<-EOF
set terminal png
set output "benchmarks/graphs/$1.rps.png"
set title "$1"
set size 0.7,0.5
set grid y
set key left top
set ylabel "requests per second"
plot "benchmarks/$1.rps.dat" using 2: xtic(1) with histogram title ""
EOF
}
mkdir -p benchmarks/graphs
for type in simple haml sass static static.large; do
plot=benchmarks/graphs/$type.p
log generating benchmarks/graphs/$type.png
line $type \
node/$type.js.dat \
express/$type.js.dat \
thin/$type.ru.dat \
> $plot
gnuplot $plot
log generating benchmarks/graphs/$type.rps.png
plot=benchmarks/graphs/$type.rps.p
dat=benchmarks/$type.rps.dat
:> $dat
for server in node express thin; do
case $server in
node|express) ext=js ;;
thin) ext=ru ;;
esac
rps=$(cat benchmarks/$server/$type.$ext.out | grep "Requests per second:" | awk '{ print $4 }')
echo $server $rps >> $dat
done
bar $type > $plot
gnuplot $plot
done
rm benchmarks/graphs/*.p

View File

@@ -0,0 +1,8 @@
var fs = require('fs'),
http = require('http')
http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': 11 })
res.end('Hello World', 'ascii')
}).listen(3000, 'localhost')

14
benchmarks/node/static.js Normal file
View File

@@ -0,0 +1,14 @@
var fs = require('fs'),
http = require('http')
http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked' })
fs.createReadStream('benchmarks/shared/jquery.js')
.addListener('data', function(data){
res.write(data, 'binary')
})
.addListener('end', function(){
res.end()
})
}).listen(3000, 'localhost')

View File

@@ -0,0 +1,14 @@
var fs = require('fs'),
http = require('http')
http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked' })
fs.createReadStream('benchmarks/shared/huge.js')
.addListener('data', function(data){
res.write(data, 'binary')
})
.addListener('end', function(){
res.end()
})
}).listen(3000, 'localhost')

61
benchmarks/run Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
SLEEP=${SLEEP-2}
ABFLAGS=${ABFLAGS-"-n 2000 -c 50"}
ADDR=${ADDR-http://127.0.0.1:3000/}
AB=${AB-ab}
#
# Log <msg ...>
#
# <msg ...>
#
log(){
echo "... $@"
}
#
# Benchmark <type> and <file>
#
# - starts the server
# - allows $SLEEP seconds for startup
# - runs $AB
# - kills the server process
#
# <type> <file>
#
bm(){
local type=$1
local file=$2
log benchmarking $type $file
case $type in
node|express)
node benchmarks/$type/$file &
;;
thin)
thin -R benchmarks/thin/$file -p 3000 start &
;;
esac
pid=$!
sleep $SLEEP
$AB $ABFLAGS -g benchmarks/$type/$file.dat $ADDR > benchmarks/$type/$file.out
log $(cat benchmarks/$type/$file.out | grep Requests)
kill -KILL $pid
}
log ab $ABFLAGS $ADDR
bm node simple.js
bm node static.js
bm node static.large.js
bm express simple.js
bm express static.js
bm express static.large.js
bm express haml.js
bm express sass.js
bm thin simple.ru
bm thin static.ru
bm thin static.large.ru
bm thin haml.ru
bm thin sass.ru

145
benchmarks/shared/huge.js Normal file

File diff suppressed because one or more lines are too long

19
benchmarks/shared/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
!!!
%html
%head
%title Wahoo
%body
#primary= yield

View File

@@ -0,0 +1,6 @@
!!!
%html
%head
%title Wahoo
%body
#primary!= body

View File

@@ -0,0 +1,10 @@
%h1 Some title
%ul
%li a
%li b
%li c
%li
%ol
%li d
%li e
%li f

View File

@@ -0,0 +1,10 @@
%h1 Some title
%ul
%li a
%li b
%li c
%li
%ol
%li d
%li e
%li f

View File

@@ -0,0 +1,73 @@
body
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
:font-size 13px
:text-align center
:color #555
h1, h2
:margin 0
:font-size 22px
:color #343434
h1
:text-shadow 1px 2px 2px #ddd
:font-size 60px
img.bubble
:position absolute
:top -25px
:left 120px
#wrapper
:position relative
:margin 100px auto
:width 500px
:text-align left
ul
:margin 0
:padding 0
:max-height 300px
:overflow-x hidden
li
:margin 5px 0
:padding 3px 8px
:list-style none
:border 1px solid #eee
li:hover
:cursor pointer
:color #2E2E2E
input[type=text]
:padding 5px
:border 1px solid #ddd
:outline none
input[type=text]:focus
:border-color #00C3FF
input[type=submit]
:padding 6px 10px
:border solid 1px #999
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
:color #333
:text-decoration none
:cursor pointer
:display inline-block
:text-align center
:text-shadow 0px 1px 1px #fff
:line-height 1
input[type=submit]:hover
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
input[type=submit]:active
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
input[name=name]
:width 80px
a
:color #1ABFF1
a:hover
:padding 0 5px
a:hover:before
:content 'visit: '
#online
:font-size 12px

14
benchmarks/thin/haml.ru Normal file
View File

@@ -0,0 +1,14 @@
require 'rubygems'
require 'sinatra'
require 'haml'
configure do
set 'views', File.dirname(__FILE__) + '/../shared'
end
get '/' do
haml :page, :ugly => true
end
run Sinatra::Application

14
benchmarks/thin/sass.ru Normal file
View File

@@ -0,0 +1,14 @@
require 'rubygems'
require 'sinatra'
require 'sass'
configure do
set 'views', File.dirname(__FILE__) + '/../shared'
end
get '/' do
sass :'style.css'
end
run Sinatra::Application

View File

@@ -0,0 +1,9 @@
require 'rubygems'
require 'sinatra'
get '/' do
'Hello World'
end
run Sinatra::Application

View File

@@ -0,0 +1,9 @@
require 'rubygems'
require 'sinatra'
get '/' do
send_file 'benchmarks/shared/huge.js'
end
run Sinatra::Application

View File

@@ -0,0 +1,9 @@
require 'rubygems'
require 'sinatra'
get '/' do
send_file 'benchmarks/shared/jquery.js'
end
run Sinatra::Application

View File

@@ -1,29 +0,0 @@
# Express examples
This page contains list of examples using Express.
- [auth](./auth) - Authentication with login and password
- [content-negotiation](./content-negotiation) - HTTP content negotiation
- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions
- [cookies](./cookies) - Working with cookies
- [downloads](./downloads) - Transferring files to client
- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs)
- [error-pages](./error-pages) - Creating error pages
- [error](./error) - Working with error middleware
- [hello-world](./hello-world) - Simple request handler
- [markdown](./markdown) - Markdown as template engine
- [multi-router](./multi-router) - Working with multiple Express routers
- [mvc](./mvc) - MVC-style controllers
- [online](./online) - Tracking online user activity with `online` and `redis` packages
- [params](./params) - Working with route parameters
- [resource](./resource) - Multiple HTTP operations on the same resource
- [route-map](./route-map) - Organizing routes using a map
- [route-middleware](./route-middleware) - Working with route middleware
- [route-separation](./route-separation) - Organizing routes per each resource
- [search](./search) - Search API
- [session](./session) - User sessions
- [static-files](./static-files) - Serving static files
- [vhost](./vhost) - Working with virtual hosts
- [view-constructor](./view-constructor) - Rendering views dynamically
- [view-locals](./view-locals) - Saving data in request object between middleware calls
- [web-service](./web-service) - Simple API service

View File

@@ -1,134 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../..');
var hash = require('pbkdf2-password')()
var path = require('node:path');
var session = require('express-session');
var app = module.exports = express();
// config
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// middleware
app.use(express.urlencoded())
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'shhhh, very secret'
}));
// Session-persisted message middleware
app.use(function(req, res, next){
var err = req.session.error;
var msg = req.session.success;
delete req.session.error;
delete req.session.success;
res.locals.message = '';
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
next();
});
// dummy database
var users = {
tj: { name: 'tj' }
};
// when you create a user, generate a salt
// and hash the password ('foobar' is the pass here)
hash({ password: 'foobar' }, function (err, pass, salt, hash) {
if (err) throw err;
// store the salt & hash in the "db"
users.tj.salt = salt;
users.tj.hash = hash;
});
// Authenticate using our plain-object database of doom!
function authenticate(name, pass, fn) {
if (!module.parent) console.log('authenticating %s:%s', name, pass);
var user = users[name];
// query the db for the given username
if (!user) return fn(null, null)
// apply the same algorithm to the POSTed password, applying
// the hash against the pass / salt, if there is a match we
// found the user
hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
if (err) return fn(err);
if (hash === user.hash) return fn(null, user)
fn(null, null)
});
}
function restrict(req, res, next) {
if (req.session.user) {
next();
} else {
req.session.error = 'Access denied!';
res.redirect('/login');
}
}
app.get('/', function(req, res){
res.redirect('/login');
});
app.get('/restricted', restrict, function(req, res){
res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
});
app.get('/logout', function(req, res){
// destroy the user's session to log them out
// will be re-created next request
req.session.destroy(function(){
res.redirect('/');
});
});
app.get('/login', function(req, res){
res.render('login');
});
app.post('/login', function (req, res, next) {
if (!req.body) return res.sendStatus(400)
authenticate(req.body.username, req.body.password, function(err, user){
if (err) return next(err)
if (user) {
// Regenerate session when signing in
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
req.session.success = 'Authenticated as ' + user.name
+ ' click to <a href="/logout">logout</a>. '
+ ' You may now access <a href="/restricted">/restricted</a>.';
res.redirect(req.get('Referrer') || '/');
});
} else {
req.session.error = 'Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")';
res.redirect('/login');
}
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><%= title %></title>
<style>
body {
padding: 50px;
font: 13px Helvetica, Arial, sans-serif;
}
.error {
color: red;
}
.success {
color: green;
}
</style>
</head>
<body>

View File

@@ -1,21 +0,0 @@
<%- include('head', { title: 'Authentication Example' }) -%>
<h1>Login</h1>
<%- message %>
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
<form method="post" action="/login">
<p>
<label for="username">Username:</label>
<input type="text" name="username" id="username">
</p>
<p>
<label for="password">Password:</label>
<input type="text" name="password" id="password">
</p>
<p>
<input type="submit" value="Login">
</p>
</form>
<%- include('foot') -%>

80
examples/chat/app.js Normal file
View File

@@ -0,0 +1,80 @@
require.paths.unshift('lib')
require('express')
require('express/plugins')
var messages = [],
utils = require('express/utils'),
http = require('express/http')
configure(function(){
use(Logger)
use(MethodOverride)
use(ContentLength)
use(Cookie)
use(Cache, { lifetime: (5).minutes, reapInterval: (1).minute })
use(Session, { lifetime: (15).minutes, reapInterval: (1).minute })
use(Static)
set('root', __dirname)
})
get('/', function(){
this.pass('/chat')
})
get('/chat', function(){
var self = this
Session.store.length(function(err, len){
self.render('chat.html.haml', {
locals: {
title: 'Chat',
messages: messages,
name: self.session.name,
usersOnline: len
}
})
})
})
post('/chat', function(){
this.session.name = this.param('name')
messages
.push(utils.escape(this.param('name')) + ': ' + utils.escape(this.param('message'))
.replace(/(http:\/\/[^\s]+)/g, '<a href="$1" target="express-chat">$1</a>')
.replace(/:\)/g, '<img src="http://icons3.iconfinder.netdna-cdn.com/data/icons/ledicons/emoticon_smile.png">'))
this.respond(200)
})
get('/chat/messages', function(){
var self = this,
previousLength = messages.length,
timer = setInterval(function(){
if (messages.length > previousLength)
self.contentType('json'),
previousLength = messages.length,
self.respond(200, JSON.encode(messages)),
clearInterval(timer)
}, 100)
})
get('/*.css', function(file){
this.render(file + '.css.sass', { layout: false })
})
get('/error/view', function(){
this.render('does.not.exist')
})
get('/error', function(){
throw new Error('oh noes!')
})
get('/simple', function(){
return 'Hello :)'
})
get('/favicon.ico', function(){
this.notFound()
})
run()

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,28 @@
$(function(){
// Send message
$('form').submit(function(){
var message = $('input[name=message]'),
name = $('input[name=name]')
if (message.val())
$.post('/chat', { name: name.val(), message: message.val() }, function(){
message.val('')
})
else
message.css('border', '1px solid red')
return false
})
// Longpoll
;(function poll(){
$.getJSON('/chat/messages', function(messages){
$('#messages').empty()
$.each(messages, function(i, msg){
$('#messages')
.append('<li>' + msg + '</li>')
.get(0).scrollTop = $('#messages').get(0).scrollHeight
})
poll()
})
})()
})

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
%h1 Chat
%img.bubble{ src: '/public/images/bubble.png' }
%ul#messages
!= this.partial('message.html.haml', { collection: messages })
%form{ method: 'post' }
%input{ type: 'hidden', name: '_method', value: 'put' }
%input{ type: 'text', name: 'name', value: name || 'guest' }
%input{ type: 'text', name: 'message' }
%input{ type: 'submit', value: 'Send' }

View File

@@ -0,0 +1,12 @@
%html
%head
%title= title
%script{ src: '/public/javascripts/jquery.js' }
%script{ src: '/public/javascripts/app.js' }
%link{ rel: 'stylesheet', href: '/style.css' }
%body
#wrapper
!= body
#online
Online:
%strong= usersOnline

View File

@@ -0,0 +1 @@
%li= message

View File

@@ -0,0 +1,81 @@
body
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
:font-size 13px
:text-align center
=text-stroke 1px rgba(255, 255, 255, 0.1)
:color #555
h1, h2
:margin 0
:font-size 22px
:color #343434
h1
:text-shadow 1px 2px 2px #ddd
:font-size 60px
img.bubble
:position absolute
:top -25px
:left 120px
#wrapper
:position relative
:margin 100px auto
:width 500px
:text-align left
ul
:margin 0
:padding 0
:max-height 300px
:overflow-x hidden
li
:margin 5px 0
:padding 3px 8px
:list-style none
:border 1px solid #eee
=border-radius 3px
=border-radius 3px
li:hover
:cursor pointer
:color #2E2E2E
input[type=text]
:padding 5px
:border 1px solid #ddd
:outline none
=border-radius 2px
input[type=text]:focus
:border-color #00C3FF
input[type=submit]
=border-radius 2px
=box-shadow 0 1px 2px #ddd
:padding 6px 10px
:border solid 1px #999
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
:color #333
:text-decoration none
:cursor pointer
:display inline-block
:text-align center
:text-shadow 0px 1px 1px #fff
:line-height 1
input[type=submit]:hover
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
input[type=submit]:active
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
input[name=name]
:width 80px
a
:color #1ABFF1
=transition-property padding
=transition-duration 0.15s
a:hover
:padding 0 5px
a:hover:before
:content 'visit: '
#online
:font-size 12px

View File

@@ -0,0 +1,38 @@
require.paths.unshift 'lib'
require 'express'
require 'express/plugins'
sys: require 'sys'
configure ->
use MethodOverride
use ContentLength
use Cookie
use Session
use Flash
use Logger
use Static
set 'root', __dirname
set 'views', __dirname + '/../upload/views'
get '/', ->
@redirect('/upload')
get '/upload', ->
@render 'upload.html.haml', {
locals: {
flashes: @flash 'info'
}
}
post '/upload', ->
@param('images').each (image) =>
sys.puts image.filename + ' -> ' + image.tempfile
@flash 'info', 'Uploaded ' + image.filename
@redirect '/upload'
get '/*.css', (file) ->
@render file + '.css.sass', { layout: no }
run()

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
'use strict'
var users = [];
users.push({ name: 'Tobi' });
users.push({ name: 'Loki' });
users.push({ name: 'Jane' });
module.exports = users;

View File

@@ -1,46 +0,0 @@
'use strict'
var express = require('../../');
var app = module.exports = express();
var users = require('./db');
// so either you can deal with different types of formatting
// for expected response in index.js
app.get('/', function(req, res){
res.format({
html: function(){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('') + '</ul>');
},
text: function(){
res.send(users.map(function(user){
return ' - ' + user.name + '\n';
}).join(''));
},
json: function(){
res.json(users);
}
});
});
// or you could write a tiny middleware like
// this to add a layer of abstraction
// and make things a bit more declarative:
function format(path) {
var obj = require(path);
return function(req, res){
res.format(obj);
};
}
app.get('/users', format('./users'));
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,19 +0,0 @@
'use strict'
var users = require('./db');
exports.html = function(req, res){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('') + '</ul>');
};
exports.text = function(req, res){
res.send(users.map(function(user){
return ' - ' + user.name + '\n';
}).join(''));
};
exports.json = function(req, res){
res.json(users);
};

View File

@@ -1,25 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var cookieSession = require('cookie-session');
var express = require('../../');
var app = module.exports = express();
// add req.session cookie support
app.use(cookieSession({ secret: 'manny is cool' }));
// do something with the session
app.get('/', function (req, res) {
req.session.count = (req.session.count || 0) + 1
res.send('viewed ' + req.session.count + ' times\n')
})
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,53 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var app = module.exports = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
// custom log format
if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used
// for signing the cookies.
app.use(cookieParser('my secret here'));
// parses x-www-form-urlencoded
app.use(express.urlencoded())
app.get('/', function(req, res){
if (req.cookies.remember) {
res.send('Remembered :). Click to <a href="/forget">forget</a>!.');
} else {
res.send('<form method="post"><p>Check to <label>'
+ '<input type="checkbox" name="remember"/> remember me</label> '
+ '<input type="submit" value="Submit"/>.</p></form>');
}
});
app.get('/forget', function(req, res){
res.clearCookie('remember');
res.redirect(req.get('Referrer') || '/');
});
app.post('/', function(req, res){
var minute = 60000;
if (req.body && req.body.remember) {
res.cookie('remember', 1, { maxAge: minute })
}
res.redirect(req.get('Referrer') || '/');
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,2 +0,0 @@
Only for test.
The file name is faked.

View File

@@ -1 +0,0 @@
what an amazing download

View File

@@ -1,3 +0,0 @@
* milk
* eggs
* bread

View File

@@ -1,40 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
// path to where the files are stored on disk
var FILES_DIR = path.join(__dirname, 'files')
app.get('/', function(req, res){
res.send('<ul>' +
'<li>Download <a href="/files/notes/groceries.txt">notes/groceries.txt</a>.</li>' +
'<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>' +
'<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>' +
'<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>' +
'</ul>')
});
// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/*file', function (req, res, next) {
res.download(req.params.file.join('/'), { root: FILES_DIR }, function (err) {
if (!err) return; // file sent
if (err.status !== 404) return next(err); // non-404 error
// file for download not found
res.statusCode = 404;
res.send('Cant find that file, sorry!');
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,57 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
// Register ejs as .html. If we did
// not call this, we would need to
// name our views foo.ejs instead
// of foo.html. The __express method
// is simply a function that engines
// use to hook into the Express view
// system by default, so if we want
// to change "foo.ejs" to "foo.html"
// we simply pass _any_ function, in this
// case `ejs.__express`.
app.engine('.html', require('ejs').__express);
// Optional since express defaults to CWD/views
app.set('views', path.join(__dirname, 'views'));
// Path to our public directory
app.use(express.static(path.join(__dirname, 'public')));
// Without this you would need to
// supply the extension to res.render()
// ex: res.render('users.html').
app.set('view engine', 'html');
// Dummy users
var users = [
{ name: 'tobi', email: 'tobi@learnboost.com' },
{ name: 'loki', email: 'loki@learnboost.com' },
{ name: 'jane', email: 'jane@learnboost.com' }
];
app.get('/', function(req, res){
res.render('users', {
users: users,
title: "EJS example",
header: "Some users"
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,4 +0,0 @@
body {
padding: 50px 80px;
font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif;
}

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -1,9 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><%= title %></title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>

View File

@@ -1,10 +0,0 @@
<%- include('header.html') -%>
<h1>Users</h1>
<ul id="users">
<% users.forEach(function(user){ %>
<li><%= user.name %> &lt;<%= user.email %>&gt;</li>
<% }) %>
</ul>
<%- include('footer.html') -%>

View File

@@ -1,103 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var path = require('node:path');
var app = module.exports = express();
var logger = require('morgan');
var silent = process.env.NODE_ENV === 'test'
// general config
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// our custom "verbose errors" setting
// which we can use in the templates
// via settings['verbose errors']
app.enable('verbose errors');
// disable them in production
// use $ NODE_ENV=production node examples/error-pages
if (app.settings.env === 'production') app.disable('verbose errors')
silent || app.use(logger('dev'));
// Routes
app.get('/', function(req, res){
res.render('index.ejs');
});
app.get('/404', function(req, res, next){
// trigger a 404 since no other middleware
// will match /404 after this one, and we're not
// responding here
next();
});
app.get('/403', function(req, res, next){
// trigger a 403 error
var err = new Error('not allowed!');
err.status = 403;
next(err);
});
app.get('/500', function(req, res, next){
// trigger a generic (500) error
next(new Error('keyboard cat!'));
});
// Error handlers
// Since this is the last non-error-handling
// middleware use()d, we assume 404, as nothing else
// responded.
// $ curl http://localhost:3000/notfound
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
app.use(function(req, res, next){
res.status(404);
res.format({
html: function () {
res.render('404', { url: req.url })
},
json: function () {
res.json({ error: 'Not found' })
},
default: function () {
res.type('txt').send('Not found')
}
})
});
// error-handling middleware, take the same form
// as regular middleware, however they require an
// arity of 4, aka the signature (err, req, res, next).
// when connect has an error, it will invoke ONLY error-handling
// middleware.
// If we were to next() here any remaining non-error-handling
// middleware would then be executed, or if we next(err) to
// continue passing the error, only error-handling middleware
// would remain being executed, however here
// we simply respond with an error page.
app.use(function(err, req, res, next){
// we may use properties of the error object
// here and next(err) appropriately, or if
// we possibly recovered from the error, simply next().
res.status(err.status || 500);
res.render('500', { error: err });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,3 +0,0 @@
<%- include('error_header') -%>
<h2>Cannot find <%= url %></h2>
<%- include('footer') -%>

View File

@@ -1,8 +0,0 @@
<%- include('error_header') -%>
<h2>Error: <%= error.message %></h2>
<% if (settings['verbose errors']) { %>
<pre><%= error.stack %></pre>
<% } else { %>
<p>An error occurred!</p>
<% } %>
<%- include('footer') -%>

View File

@@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Error</title>
</head>
<body>
<h1>An error occurred!</h1>

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Custom Pages Example</title>
</head>
<body>
<h1>My Site</h1>
<h2>Pages Example</h2>
<ul>
<li>visit <a href="/500">500</a></li>
<li>visit <a href="/404">404</a></li>
<li>visit <a href="/403">403</a></li>
</ul>
</body>
</html>

View File

@@ -1,53 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../');
var logger = require('morgan');
var app = module.exports = express();
var test = app.get('env') === 'test'
if (!test) app.use(logger('dev'));
// error handling middleware have an arity of 4
// instead of the typical (req, res, next),
// otherwise they behave exactly like regular
// middleware, you may have several of them,
// in different orders etc.
function error(err, req, res, next) {
// log it
if (!test) console.error(err.stack);
// respond with 500 "Internal Server Error".
res.status(500);
res.send('Internal Server Error');
}
app.get('/', function () {
// Caught and passed down to the errorHandler middleware
throw new Error('something broke!');
});
app.get('/next', function(req, res, next){
// We can also pass exceptions to next()
// The reason for process.nextTick() is to show that
// next() can be called inside an async operation,
// in real life it can be a DB read or HTTP request.
process.nextTick(function(){
next(new Error('oh no!'));
});
});
// the error handler is placed after routes
// if it were above it would not receive errors
// from app.get() etc
app.use(error);
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -0,0 +1,19 @@
require.paths.unshift('lib')
require('express')
configure(function(){
set('root', __dirname)
})
get('/', function(){
this.render('front.html.ejs', {
locals: {
title: 'Hello World',
name: 'Joe',
items: ['one', 'two', 'three']
}
})
})
run()

View File

@@ -1,15 +0,0 @@
'use strict'
var express = require('../../');
var app = module.exports = express()
app.get('/', function(req, res){
res.send('Hello World');
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -0,0 +1,9 @@
<h1><%= title %></h1>
<%= this.partial("greeting.html.ejs", { locals: { name: name } }) %>
<% if (items && items.length) { %>
<ul>
<% for (var i = 0; i < items.length; ++i) { %>
<li><%= items[i] %></li>
<% } %>
</ul>
<% } %>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title><%= title %></title>
</head>
<body>
<%= body %>
</body>
</html>

View File

@@ -0,0 +1 @@
Welcome back, <strong><%= name %></strong>!

View File

@@ -1,44 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var escapeHtml = require('escape-html');
var express = require('../..');
var fs = require('node:fs');
var marked = require('marked');
var path = require('node:path');
var app = module.exports = express();
// register .md as an engine in express view system
app.engine('md', function(path, options, fn){
fs.readFile(path, 'utf8', function(err, str){
if (err) return fn(err);
var html = marked.parse(str).replace(/\{([^}]+)\}/g, function(_, name){
return escapeHtml(options[name] || '');
});
fn(null, html);
});
});
app.set('views', path.join(__dirname, 'views'));
// make it the default, so we don't need .md
app.set('view engine', 'md');
app.get('/', function(req, res){
res.render('index', { title: 'Markdown Example' });
});
app.get('/fail', function(req, res){
res.render('missing', { title: 'Markdown Example' });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,4 +0,0 @@
# {title}
Just an example view rendered with _markdown_.

View File

@@ -1,15 +0,0 @@
'use strict'
var express = require('../../..');
var apiv1 = express.Router();
apiv1.get('/', function(req, res) {
res.send('Hello from APIv1 root route.');
});
apiv1.get('/users', function(req, res) {
res.send('List of APIv1 users.');
});
module.exports = apiv1;

View File

@@ -1,15 +0,0 @@
'use strict'
var express = require('../../..');
var apiv2 = express.Router();
apiv2.get('/', function(req, res) {
res.send('Hello from APIv2 root route.');
});
apiv2.get('/users', function(req, res) {
res.send('List of APIv2 users.');
});
module.exports = apiv2;

View File

@@ -1,18 +0,0 @@
'use strict'
var express = require('../..');
var app = module.exports = express();
app.use('/api/v1', require('./controllers/api_v1'));
app.use('/api/v2', require('./controllers/api_v2'));
app.get('/', function(req, res) {
res.send('Hello from root route.')
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,5 +0,0 @@
'use strict'
exports.index = function(req, res){
res.redirect('/users');
};

View File

@@ -1,31 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var db = require('../../db');
exports.engine = 'ejs';
exports.before = function(req, res, next){
var pet = db.pets[req.params.pet_id];
if (!pet) return next('route');
req.pet = pet;
next();
};
exports.show = function(req, res, next){
res.render('show', { pet: req.pet });
};
exports.edit = function(req, res, next){
res.render('edit', { pet: req.pet });
};
exports.update = function(req, res, next){
var body = req.body;
req.pet.name = body.pet.name;
res.message('Information updated!');
res.redirect('/pet/' + req.pet.id);
};

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title>Edit <%= pet.name %></title>
</head>
<body>
<h1><%= pet.name %></h1>
<form action="/pet/<%= pet.id %>?_method=put" method="post">
<label>Name: <input type="text" name="pet[name]" value="<%= pet.name %>"></label>
<input type="submit" value="Update">
</form>
</body>
</html>

View File

@@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title><%= pet.name %></title>
</head>
<body>
<h1><%= pet.name %> <a href="/pet/<%= pet.id %>/edit">edit</a></h1>
<p>You are viewing <%= pet.name %></p>
</body>
</html>

View File

@@ -1,22 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var db = require('../../db');
exports.name = 'pet';
exports.prefix = '/user/:user_id';
exports.create = function(req, res, next){
var id = req.params.user_id;
var user = db.users[id];
var body = req.body;
if (!user) return next('route');
var pet = { name: body.pet.name };
pet.id = db.pets.push(pet) - 1;
user.pets.push(pet);
res.message('Added pet ' + body.pet.name);
res.redirect('/user/' + id);
};

View File

@@ -1,41 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var db = require('../../db');
exports.engine = 'hbs';
exports.before = function(req, res, next){
var id = req.params.user_id;
if (!id) return next();
// pretend to query a database...
process.nextTick(function(){
req.user = db.users[id];
// cant find that user
if (!req.user) return next('route');
// found it, move on to the routes
next();
});
};
exports.list = function(req, res, next){
res.render('list', { users: db.users });
};
exports.edit = function(req, res, next){
res.render('edit', { user: req.user });
};
exports.show = function(req, res, next){
res.render('show', { user: req.user });
};
exports.update = function(req, res, next){
var body = req.body;
req.user.name = body.user.name;
res.message('Information updated!');
res.redirect('/user/' + req.user.id);
};

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title>Edit {{user.name}}</title>
</head>
<body>
<h1>{{user.name}}</h1>
<form action="/user/{{user.id}}?_method=put" method="post">
<label for="user[name]">Name:
<input type="text" name="user[name]" value="{{user.name}}">
</label>
<input type="submit" name="submit" value="Update">
</form>
<form action="/user/{{user.id}}/pet" method="post">
<label for="pet[name]">Pet:
<input type="text" name="pet[name]" placeholder="Pet Name">
</label>
<input type="submit" name="submit" value="Add">
</form>
</body>
</html>

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title>Users</title>
</head>
<body>
<h1>Users</h1>
<p>Click a user below to view their pets.</p>
<ul>
{{#each users}}
<li><a href="/user/{{id}}">{{name}}</a></li>
{{/each}}
</ul>
</body>
</html>

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title>{{user.name}}</title>
</head>
<body>
<h1>{{user.name}} <a href="/user/{{user.id}}/edit">edit</a></h1>
{{#if hasMessages}}
<ul>
{{#each messages}}
<li>{{this}}</li>
{{/each}}
</ul>
{{/if}}
{{#if user.pets.length}}
<p>View {{user.name}}'s pets:</p>
<ul>
{{#each user.pets}}
<li><a href="/pet/{{id}}">{{name}}</a></li>
{{/each}}
</ul>
{{else}}
<p>No pets!</p>
{{/if}}
</body>
</html>

View File

@@ -1,16 +0,0 @@
'use strict'
// faux database
var pets = exports.pets = [];
pets.push({ name: 'Tobi', id: 0 });
pets.push({ name: 'Loki', id: 1 });
pets.push({ name: 'Jane', id: 2 });
pets.push({ name: 'Raul', id: 3 });
var users = exports.users = [];
users.push({ name: 'TJ', pets: [pets[0], pets[1], pets[2]], id: 0 });
users.push({ name: 'Guillermo', pets: [pets[3]], id: 1 });
users.push({ name: 'Nathan', pets: [], id: 2 });

View File

@@ -1,95 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var path = require('node:path');
var session = require('express-session');
var methodOverride = require('method-override');
var app = module.exports = express();
// set our default template engine to "ejs"
// which prevents the need for using file extensions
app.set('view engine', 'ejs');
// set views for error and 404 pages
app.set('views', path.join(__dirname, 'views'));
// define a custom res.message() method
// which stores messages in the session
app.response.message = function(msg){
// reference `req.session` via the `this.req` reference
var sess = this.req.session;
// simply add the msg to an array for later
sess.messages = sess.messages || [];
sess.messages.push(msg);
return this;
};
// log
if (!module.parent) app.use(logger('dev'));
// serve static files
app.use(express.static(path.join(__dirname, 'public')));
// session support
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'some secret here'
}));
// parse request bodies (req.body)
app.use(express.urlencoded({ extended: true }))
// allow overriding methods in query (?_method=put)
app.use(methodOverride('_method'));
// expose the "messages" local variable when views are rendered
app.use(function(req, res, next){
var msgs = req.session.messages || [];
// expose "messages" local variable
res.locals.messages = msgs;
// expose "hasMessages"
res.locals.hasMessages = !! msgs.length;
/* This is equivalent:
res.locals({
messages: msgs,
hasMessages: !! msgs.length
});
*/
next();
// empty or "flush" the messages so they
// don't build up
req.session.messages = [];
});
// load controllers
require('./lib/boot')(app, { verbose: !module.parent });
app.use(function(err, req, res, next){
// log it
if (!module.parent) console.error(err.stack);
// error page
res.status(500).render('5xx');
});
// assume 404 since no middleware responded
app.use(function(req, res, next){
res.status(404).render('404', { url: req.originalUrl });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,83 +0,0 @@
'use strict'
/**
* Module dependencies.
*/
var express = require('../../..');
var fs = require('node:fs');
var path = require('node:path');
module.exports = function(parent, options){
var dir = path.join(__dirname, '..', 'controllers');
var verbose = options.verbose;
fs.readdirSync(dir).forEach(function(name){
var file = path.join(dir, name)
if (!fs.statSync(file).isDirectory()) return;
verbose && console.log('\n %s:', name);
var obj = require(file);
var name = obj.name || name;
var prefix = obj.prefix || '';
var app = express();
var handler;
var method;
var url;
// allow specifying the view engine
if (obj.engine) app.set('view engine', obj.engine);
app.set('views', path.join(__dirname, '..', 'controllers', name, 'views'));
// generate routes based
// on the exported methods
for (var key in obj) {
// "reserved" exports
if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;
// route exports
switch (key) {
case 'show':
method = 'get';
url = '/' + name + '/:' + name + '_id';
break;
case 'list':
method = 'get';
url = '/' + name + 's';
break;
case 'edit':
method = 'get';
url = '/' + name + '/:' + name + '_id/edit';
break;
case 'update':
method = 'put';
url = '/' + name + '/:' + name + '_id';
break;
case 'create':
method = 'post';
url = '/' + name;
break;
case 'index':
method = 'get';
url = '/';
break;
default:
/* istanbul ignore next */
throw new Error('unrecognized route: ' + name + '.' + key);
}
// setup
handler = obj[key];
url = prefix + url;
// before middleware support
if (obj.before) {
app[method](url, obj.before, handler);
verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), url, key);
} else {
app[method](url, handler);
verbose && console.log(' %s %s -> %s', method.toUpperCase(), url, key);
}
}
// mount the app
parent.use(app);
});
};

View File

@@ -1,14 +0,0 @@
body {
padding: 50px;
font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif;
}
a {
color: #107aff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1 a {
font-size: 16px;
}

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Not Found</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>404: Not Found</h1>
<p>Sorry we can't find <%= url %></p>
</body>
</html>

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Internal Server Error</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>500: Internal Server Error</h1>
<p>Looks like something blew up!</p>
</body>
</html>

View File

@@ -1,61 +0,0 @@
'use strict'
// install redis first:
// https://redis.io/
// then:
// $ npm install redis online
// $ redis-server
/**
* Module dependencies.
*/
var express = require('../..');
var online = require('online');
var redis = require('redis');
var db = redis.createClient();
// online
online = online(db);
// app
var app = express();
// activity tracking, in this case using
// the UA string, you would use req.user.id etc
app.use(function(req, res, next){
// fire-and-forget
online.add(req.headers['user-agent']);
next();
});
/**
* List helper.
*/
function list(ids) {
return '<ul>' + ids.map(function(id){
return '<li>' + id + '</li>';
}).join('') + '</ul>';
}
/**
* GET users online.
*/
app.get('/', function(req, res, next){
online.last(5, function(err, ids){
if (err) return next(err);
res.send('<p>Users online: ' + ids.length + '</p>' + list(ids));
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

Some files were not shown because too many files have changed in this diff Show More