Skip to content

Instantly share code, notes, and snippets.

@rob137
Created January 11, 2018 09:44
Show Gist options
  • Save rob137/dcc044fd9eebfa25fd98fe0c1c35cac9 to your computer and use it in GitHub Desktop.
Save rob137/dcc044fd9eebfa25fd98fe0c1c35cac9 to your computer and use it in GitHub Desktop.
Thinkful Back-end Notes
Connect to the database,
then start the server,
then seed the database with test data,
then make a request to the API,
then inspect the response,
then inspect the state of the database.
function doMyTest() {
let db, server;
return connectToDb // Note that connectToDb isn't defined...
//Connect to the database,
.then(_db => {
db = _db
return startServer()
})
//then start the server,
.then(_server => {
server = _server;
return seedData(db);
})
//then seed the database with test data,
.then(() => {
return makeTestRequestToApi(server);
})
//then make a request to the API,
.then(response => {
// do stuff to inspect response object
return queryDb()
})
//then inspect the response,
.then(queryResult => {
// inspect query result
})
//then inspect the state of the database.
.catch(error => {
// do something about the error
});
}
// The above takes the form:
function doStuff() {
return doSomething // Note that doSomething isn't defined...
.then(function() {
[some stuff]
})
.then(function() {
}).then(
[etc..]
);
}
// bad version:
function doMyTest(done) {
connectToDb(startServer(seedData(makeTestRequestToApi(inspectResponse(inspectDb(done))))));
}
THE SERVER MODEL:
_________________________________________
| | Server-side Programming is about:
| Server | Routing (requests to handlers)
| ['back-end'] | Data Persistence
| _______________ | Business Logic
| | | | Security
| | Database | | Software Testing
| | [files] | | DevOps
| | [API data] | |
| | | |
| |_______________| __________ |
| | | | |
| | | Static | |
| ______|_______ | Assets | |
| | | | | |
| | (Optional | | | |
| | Middleware) | | - HTML | |
| | Request | | - CSS | |
| | Handler |----| - JS | |
| | ______ | | - etc | |
| | | | | |__________| |
|____|___| PORT |___|_____________________|
|______| **Status codes in responses:
1xx - Informational
2xx - Success (200 is HTTP response default)
^ | 3xx - Redirection
| | 4xx - Client error
HTTP | | Response** 5xx - Server error
request*| |
| v
*Request verbs: (In Express:)
_______________ GET* ie 'read' app.get
| | HEAD app.head
| Client | POST* ie 'create' app.post
| ['front-end'] | PUT* ie 'replace' app.push
|_______________| DELETE* app.delete
CONNECT app.connect
OPTIONS app.options
TRACE app.trace
PATCH* ie 'update'
|____________________________________________________________|
|
['fullstack']
The key parts of a modern server app:
- A way to listen for HTTP requests over a port: app.listen
- A way to inspect and interact with HTTP requests and responce objects: /public
- A way to route HTTP requests from clients to the right request handlers: app.get
- A way to serve static assets to client browsers: app.use(express.static('public'))
- A way to serve data to clients: app.get('/address', (req, res) =>) {}
To serve static assets, you need:
// load express and create your app
const express = require('express');
const app = express();
// set up your folder 'public' for static assets
app.use(express.static('public'));
// set up a response to get requests from clients
app.get("/", (request, response) => {
response.sendFile(__dirname + '/views/index.html');
});
// tell your server to start listening on a port
app.listen(process.env.PORT, () => {
console.log('Your app is listening on port ${process.env.PORT}');
});
"It's possible to set up more than one static folder."
https://www.example.com:8080/catpics/cats.html?name=value&foo-bar#anchor
____ _ _____ _ ___ _____ _______ _________________ _____
| | | | | | | | |
Scheme | Domain | Port | File Querystring Fragment
(protocol) | | File (hash)
| Top level path
Sub-domain domain
- Go over difference between promises/callbacks/observables and get back to LM with any questions...
'REST API' stands for Representational State Transfer Application Programming Interface...
RESTful APIs expose resources through URLs.
The industry convention: endpoints are _nouns_ (e.g. /users/) and HTTP methods are _verbs_ (GET, POST, DELETE, PATCH, PUT etc)
'CRUD' stand for the four most common REST API operations:
_C_reating new resources. (POST)
_R_eading existing resources. (GET)
_U_pdating resources. (PUT)
_D_eleting resources. (DELETE)
Make APIs 'thin' - as far as possible, put the necessary conditional logic in your models instead.
When routing becomes at all complicated in server.js, use Express to create separate router files for each '/address'. This is called 'modularisation'.
TYPICAL COMMANDS TO START OWN WEB DEVELOPMENT PROJECT
mkdir [folder] && cd [folder]
npm init // prepare basic suite of packages
git init
echo "node_modules" > .gitignore // tell git to ignore node_modules
git add .gitignore // tell git to ignore node_modules
git add package.json
git commit -m 'initial commit'
npm test // run mocha/chai tests
nodemon server.js // run server
heroku create // setup heroku server
git push heroku master // push files to heroku server
heroku open // open app in browser
heroku logs --tail // show logs!
Heroku allows you to _deploy_ an app. Allows you to host.
TYPICAL COMMANDS TO CLONE WEB DEVELOPMENT PROJECT
Create reposititory on GitHub.
CD to folder on local.
git init
git add (any file)
git commit -m 'initial commit'
git remote set-url origin ___ [ssh address from repository on Github]
git push
npm install // download necessary dependencies
nodemon server.js // run server
REQUIREMENTS FOR BLOG API
Your app should support the four CRUD operations for a blog posts resource.
GET and POST requests should go to /blog-posts.
DELETE and PUT requests should go to /blog-posts/:id.
Use Express router and modularize routes to /blog-posts.
Add a couple of blog posts on server load so you'll automatically have some data to look at when the server starts.
Mocha: test framework for unit testing.
after npm init:
npm install mocha --save-dev
"Note that, by default, Mocha recusively looks for .js files in a 'test' folder. By convention, we name our test files with lowercase, dash-separated text beginning with test-."
Chai: test framework for integration testing.
Try deploying a project on Heroku to help you remember how it all works.
Mongo:
mongod // in one tab to init mongo
mongo // in another tab to init mongo console
db
show dbs
use somedatabase // switch to a database (eg somedatabase)
db.getCollectionNames() // Show collections in current database
db.restaurants.findOne() // Show a document in a collection. (eg restaurants)
db.restaurants.insertOne(myRestaurant) // add document to collection (eg myRestaurant to restaurants)
db.restaurants.insertMany([arrayofrestaurants])
db.restaurants.insert(whatever) // will inset 1x object or arr, depending on what you give it
db.myCollection.find() // returns all results in collection (eg myCollection)
// .find returns a _cursor_ object
db.restaurants.
find({borough: "Manhattan"}, {_id: 1, name: 1, address: 1}).
sort({name: 1}).
limit(5);
// find within the restaurants collection: { key/value details }; sort by name; show first 5 results
// to find a document by its id:
var someId = ObjectId("59074c7c057aaffaafb0dcc1");
db.restaurants.findOne({_id: someId});
// to update an object:
// find an obj and get its id:
var objectId = db.restaurants.findOne({}, {_id: 1})._id;
// use the id to update with '$'
db.restaurants.updateOne(
{_id: objectId},
{$set: {name: "Foo Bar"}}
);
// to see the changes
db.restaurants.findOne({_id: objectId});
// replaceOne works the same way as updateOne. Fully replaces document.
db.restaurants.replaceOne(
{_id: objectId},
{name: "Yummo's"}
);
// deleting:
.deleteOne
.deleteMany
db.myCollection.remove() // note that it defaults to deleting all documents that meet criteria
// so use
db.restaurants.remove({_id: objectId}); // using id ensures you only remove a single document
Exercises:
Get all
Find the command that retrieves all restaurants.
db.restaurants.find()
Limit and sort
Find the command that makes the first 10 restaurants appear when db.restaurants is alphabetically sorted by the name property.
db.restaurants.
find().
sort({name: 1}).
limit(10)
Get by _id
Retrieve a single restaurant by _id from the restaurants collection. This means you'll first need to get the _id for one of the restaurants imported into the database.
var exampleId = db.restaurants.findOne({}, {_id: 1})._id;
db.restaurants.findOne({_id: exampleId});
Get by value
Write a command that gets all restaurants from the borough of "Queens".
db.restaurants.find({borough: "Queens"});
Count
Write a command that gives the number of documents in db.restaurants.
db.restaurants.count()
Count by nested value
Write a command that gives the number of restaurants whose zip code value is '11206'. Note that this property is at document.address.zipcode, so you'll need to use dot notation to query on the nested zip code property.
db.restaurants.find({"address.zipcode": "11206"}).count();
Delete by id
Write a command that deletes a document from db.restaurants. This means you'll first need to get the _id for one of the restaurants imported into the database.
var exampleId = db.restaurants.findOne()._id;
db.restaurants.remove({"_id": exampleId});
Update a single document
Write a command that sets the name property of a document with a specific _id to 'Bizz Bar Bang'. Make sure that you're not replacing the existing document, but instead updating only the name property.
var exampleId = db.restaurants.findOne()._id
db.restaurants.updateOne(
{"_id": exampleId},
{$set: {"name": "Bizz Bar Bang"}}
);
Update many documents
Uh oh, two zip codes are being merged! The '10035' zip code is being retired, and addresses with '10035' will now fall under the '10036' zip code. Write a command that updates values accordingly.
var oldZipcodeRestaurants = db.restaurants.find({"address.zipcode": "10035"});
db.restaurants.update (
{"address.zipcode": "10035"},
{$set: {"address.zipcode": "10036"}},
{"multi": "true"}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment