Table of Contents
Problem
You want the server to provide standard REST endpoints to the site.
Solution
Create routes in /server/routes/index.coffee
, using pre-existing or custom middleware in /server/middleware
.
Details
The routes we usually include for a collection are:
- Create:
POST /db/collection_name
- Get many:
GET /db/collection_name
- Get one:
GET /db/collection_name/:id
- Edit one:
PUT /db/collection_name/:id
Some collections may also allow DELETE, though that's uncommon. Others may not need all of these, such as one which allows creation but not editing.
General vs Custom Behavior
There are generic handlers for standard behavior in /server/middleware/rest.coffee
, and if possible, your endpoints should just use those. If your endpoint needs custom behavior, though, you can use rest.coffee
as a template for specific middleware, such as for the PUT Achievement middleware.
You can also extend route behavior by chaining middleware, such as these Achievement POST and GET routes do. The GET middleware fetchByRelated
checks if there's a related
is a GET query parameter. If there is, it handles the response, otherwise it continues to the generic rest GET middleware.
app.get('/db/achievement', mw.achievements.fetchByRelated, mw.rest.get(Achievement))
While the POST middleware prevents anyone but admins or artisans from performing the action.
app.post('/db/achievement', mw.auth.checkHasPermission(['admin', 'artisan']), mw.rest.post(Achievement))
Generators and Yield
To avoid callback hell, we use co
, which is elegantly tied to express
with co-express
. Async functions should return Promises, and then yielded to co. Mongoose commands like find
and save
return Promise-like Query objects. If you need to make a Node-style callback function into a Promise, use Bluebird. When errors happen, they are automatically given to Express' next
function and sent to our error middleware.
For an elegant explanation of what's going on when you use co
and yield
, read Node.js Flow (part 2) - Fibers and Generators by Eirik Vullum.
wrap = require 'co-express'
# this function is express middleware that can be put into any routes
module.exports.setSomeValue: wrap (req, res) ->
doodad = yield Doodad.findById(req.query.userID)
doodad.set('property', 'value')
yield doodad.save()
res.status(200).send(doodad.toObject())
Resources
- Home
- Archmage Home
- Artisan Home
- Adventurer Home
- Scribe Home
- Diplomat Home
- Ambassador Home
- Archmage General
- Mission statement
- Coco Models
- Coding Guidelines
- Cookbook
- File system
- JSON Schema
- Technical overview
- Testing
- Third party software and services
- Artisan General
- Building A Level
- Coding Guidelines for Artisans
- Editing Thang Components
- Important Artisan Concepts
- Keyboard Shortcuts
- Artisan How-To Index
- Adventurer General
- Scribe General
- Diplomat General
- i18n
- i18n Glossary nb
- i18n Glossary ru
- i18n Glossary es-419
- Ambassador General
- Dev Setup
- Dev Setup: Linux
- Dev Setup: Windows
- Dev Setup: Mac
- Dev Setup: Vagrant
- Dev Setup: Issues
- Game Engine
- Component
- Multiplayer
- Surface
- System
- Thang
- Thang Component System
- Tome
- World
- Artisan Tabs
- Components And Systems
- Scripts
- Settings
- Thangs
- Other
- Aether
- Client models
- Developer organization
- Educational Standards
- Events, subscriptions, shortcuts
- Chat Room
- Chat Room Rules
- Permissions
- Project Ideas List
- Treema
- Versioning
- Views
CodeCombat | Home | Blog | Forum | Teachers | Legal | Contribute