freeCodeCamp / CurriculumExpansion

Creative Commons Attribution Share Alike 4.0 International
309 stars 104 forks source link

Back End Challenges #26

Closed ghost closed 7 years ago

ghost commented 8 years ago

These should replace express-works.

Proposed Challenges:

ChaituVR commented 8 years ago

Hey @atjonathan how about some challenges on Sessions , Cookies etc... As all the projects in Dynamic Web Application Projects needs these and these are one of major topics in web development (specially for guys coming from PHP background it maybe little hard to understand them)

ghost commented 8 years ago

@ChaituVR, sure defiantly! What others would like to be added?

ChaituVR commented 8 years ago

Here are some thoughts i got.. (if there is some way to implement)

ChaituVR commented 8 years ago

There are a lot more actually.. But we should consider the possibilities of creating them.. Whats going wrong is that.. We have a lot of frontend challenges.. Projects.. Etc.. And once some guy finishes it or ignore some part and goes to backend.. We are asking him to go to c9 or command line or modules like how-to-npm or other which are really confusing to some people. Who never used them before..

ghost commented 8 years ago

@ChaituVR, we are hoping to have a multi file editor soon, which will cater for these kind of challenges. This list looks solid, are you interested in helping with development?

ChaituVR commented 8 years ago

Yes ofcourse i am interested but i had no idea what to or where to.. I am going through this repo from last four days so that i can find some way contribute..

ghost commented 8 years ago

@ChaituVR Awesome :smile: The best way to contribute for this kinda thing is to comment with the name of each challenge, challenge description, challenge seed, solution and tests!

ChaituVR commented 8 years ago

Yes great :) i hope i can comment few more on other issues too.. And if there is some work needed with development.. I am interested.. You can msg me on gitter or i can msg you if you want me to :) lets end this long conversation on the issue ( people may feel hard reading all this stuff)

ChaituVR commented 8 years ago

Hello NodeJs

Challenge Description Once you installed Nodejs in your system or C9 you'll have access to a new command called node. You can use the node command in two different ways. The first is with no arguments type node in the command-line This will open an interactive shell (REPL: read-eval-print-loop) where you can execute raw JavaScript code.

``` $ node > console.log('Hello World'); Hello World undefined ``` In the above example I typed "console.log('Hello World')" into the shell and hit enter. Node will then execute that code and we can see our logged message. It also prints "undefined" because it displays the return value of each command and console.log doesn't return anything. **Challenge Seed**

Challenge Tests

Challenge Solution

console.log('Hello World');

Src- http://blog.modulus.io/absolute-beginners-guide-to-nodejs

ChaituVR commented 8 years ago

Hello NodeJs from Javascript File

Challenge Description

The other way to run Node is by providing it a JavaScript file to execute. This is almost always how you'll be using it. Create a file " hello.js " and type

console.log('Hello World');

and execute the following file with

$node hello.js

Node then runs the JavaScript in that file and prints "Hello World".

Challenge Seed

Challenge Tests

Challenge Solution

console.log('Hello World');

Src- http://blog.modulus.io/absolute-beginners-guide-to-nodejs

ChaituVR commented 8 years ago

REPL Terminal

Challenge Description

REPL stands for Read Eval Print Loop and it represents a computer environment like a window console or Unix/Linux shell where a command is entered and system responds with an output. R - Reads user input, parse the input into JavaScript data-structure and stores in memory. E - Takes and evaluates the data structure P - Prints the result L - Loops the above command until user press ctrl-c twice.

It is very useful in experimenting with Node.js codes and to debug JavaScript codes.

REPL can be started by simply running node on shell without any argument

$ node

Play with it for some time Try doing some Mathematical operations like

$ node
> 10 + 3
13
> 20 + (  5 * 3 ) - 10
25
>

try JavaScript

$ node
> x = 10
10
> var y = 10
undefined
> x + y
20
> 3 > 2 > 1
false
> console.log("Node is Cool...!")
Node is Cool...!
undefined

You can terminate your REPL any time by pressing ctrl + c twice

Src- http://www.tutorialspoint.com/nodejs/nodejs_repl_terminal.htm

ChaituVR commented 8 years ago

Modules

Challenge Description

A Module is a separate piece of code that you need to include in your program. It could be your own module or someone else's module. Node.js has several modules compiled into the binary. For example http module to create a server or fs for file system

The keyword require is used in Node.js to import modules

var moduleX = require("path to the file")

For this challenge include http module into your program and assign it to a variable "http".

Remember that http is the core module so you can give only its name as path

Challenge Seed

Challenge Tests

Challenge Solution

var http = require('http')

ChaituVR commented 8 years ago

Create your own Module

Challenge Description

In this Challenge we will create our own module and use it in another program by importing it Create two files reverse.js (As our module) and main.js as our main program file

In `reverse.js' add your function to reverse the given name as a parameter

function reverseName(name){
  return //your code to reverse a string
}
module.exports.reverseName=reverseName;

Here 'module.exports' Exports your code

Now Import this file into your main.js file using require( ) and assign it to a variable " reverse" . As the reverse.js is in same folder you should use ./ as the path before the name of the file.

then finally your reverse module is available in your main.js console log your reverseName function with a string for example:

console.log(reverse.reverseName("cat"));

which should output "tac". Challenge Seed

Challenge Tests

Challenge Solution

reverse.js

function reverseName(name){
  return name.split('').reverse().join('');
}
module.exports.reverseName=reverseName;

main.js

var reverse=require("./reverse.js")
console.log(reverse.reverseName("cat"));
Daynil commented 8 years ago

Serving with ExpressJS

Challenge Description

Express helps you respond to client-side requests for information. If you visit a website created with express, express will analyze the route in the address bar to determine what to do next.

The first part of a URL is called the base URL of a website. When a user visits a route on their browser, the browser automatically issues a GET request to the server at the route typed in the URL. If you only type the base URL, you are issuing the request at the / route of the server. For example, when you type:

http://www.helloworld.com/

The browsers issues a GET request to the / route of the server located at www.helloworld.com.

The job of a web server is to issue either a web page or information such as a JSON object, a number, or a string when a client makes a request. The simplest possible express server that serves 'Hello world' in the form of an HTML web page looks like this:

var express = require('express');
var app = express();

app.get('/', function(request, response) {
    response.send('<p>Hello World!</p>');
});

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

In this app, you load the express library, then initialize an express app. You tell express that when a client requests the base URL of your web server, you send them the string '<p>Hello World!</p>'. The client's browser then receives this string and renders it to the web browser as a paragraph tag in the body of the browser's HTML. The last block of code tells your express app what port on your computer your server will respond to requests from. If you are serving from your home computer, that means it serves at the IP address of your computer on the world wide web, and a specific port on that computer.

Instructions

In your code, try sending the string 'Big Hello!!' in an h1 tag when the client sends a GET request to your server at the /bighello route.

Seed code

var express = require('express');
var app = express();

app.get('/', function(request, response) {
    response.send('<p>Hello World!</p>');
});

// Enter code below this line

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Solution

var express = require('express');
var app = express();

app.get('/', function(request, response) {
    response.send('<p>Hello World!</p>');
});

// Enter code below this line

app.get('/bighello', function(request, response) {
  response.send('<h1>Big Hello!!</h1>');
});

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Tests

var request = require('request');
var base_url = 'http://localhost:3000/';

describe('Hello world server', function() {
  describe('GET /bighello', function() {
    it('returns status code 200', function(done) {
      request.get(base_url+'bighello', function(err, res, body) {
        expect(res.statusCode).toBe(200);
        done();
      });
    });

    it('has Big Hello!! in h1 tags in body', function(done) {
      request.get(base_url+'bighello', function(err, res, body) {
        expect(body).toBe('<h1>Big Hello!!</h1>');
        done();
      });
    });
  });
});
Daynil commented 8 years ago

I'm not sure how these backend challenges will be implemented with the current technology so I don't know how to write the seed code or tests.

@atjonathan you stated `we are hoping to have a multi file editor soon, which will cater for these kind of challenges'. Does that mean you can have one file with 'client-side' code making requests and one with 'server-side' code issuing responses?

How would you structure seed code or tests using an in-browser editor like the one FCC uses? One thought would be making it a faux-server that sends a 'response' to the console based on what the user typed for their code, but it seems like we're missing the bigger picture doing it that way. We need to understand that the server is a separate entity sending things that the browser then renders, and I'm not sure how that would look with the in browser editor?

QuincyLarson commented 8 years ago

@Daynil We may seek to mimic some of HyperDev's functionality on FCC. It's possible that REPL.it or another technology will allow us to run back end code in the browser using containers or a similar technology.

So see if you can implement some challenges on HyperDev and then we can figure out a way to get those running on FCC.

QuincyLarson commented 8 years ago

@atjonathan my suggestion would be to leave out Pug since it's entirely optional. Better to focus on teaching raw HTML that works anywhere. Keep in mind that when campers hit the back end challenges, they will only have 800 hours of development experience and they could still use a lot more practice with HTML.

QuincyLarson commented 8 years ago

@ChaituVR some of these things you listed could be part of our security challenges section (which will come after these backend challenges): https://github.com/FreeCodeCamp/CurriculumExpansion/issues/25

ChaituVR commented 8 years ago

@QuincyLarson Yea i guess

are part of the security challenges #25 if possible I will try to comment some challenges there with some detailed description :)

ghost commented 8 years ago

@quincylarson we should teach ejs instead of pug then :+1:

Daynil commented 7 years ago

@QuincyLarson HyperDev looks awesome, I'll work on some more basic backend challenges with this framework in mind!

@atjonathan I agree with Quincy that we should avoid template engines in favor of vanilla HTML. Trying to learn a template engine while learning the very basics of node is putting the cart before the horse, not to mention FCC is very front-end heavy so most users will utilize node/express as a thin API layer to interface with their databases and won't need templating in their html from the backend at all.

ghost commented 7 years ago

@Daynil, agreed.

Daynil commented 7 years ago

Sending a file

Challenge Description

You'll want to send more than just simple strings with your express application. Luckily, express provides ways for you to do just that. Instead of serving a string, you can serve a file containing html, like myhomepage.html.

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/myhomepage.html');
});

If you want users to see your homepage when they visit your base URL, you instruct express to send the desired file as the response to the GET request that the browser makes when a user visits your website.

__dirname is a special node variable that represents the string of the directory where the current script (in this case, the express server script) resides. If your myhomepage.html resides in the same folder as your server, you would tell express to serve from the name of the current directory __dirname plus the name of the file within that folder that you want to serve.

Instructions

If your myhomepage.html has a link to another page on your website called about, a user clicking that link would send a GET request to the route /about. In your code, serve up the file aboutpage.html in response to a request to that route.

Seed code

var express = require('express');
var app = express();

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/myhomepage.html');
});

// Enter code below this line

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Solution

var express = require('express');
var app = express();

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/myhomepage.html');
});

// Enter code below this line

app.get("/about", function (request, response) {
  response.sendFile(__dirname + '/aboutpage.html');
});

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Tests

var fs = require('fs');
var request = require('request');
var base_url = 'http://localhost:3000/';
var aboutpg = fs.readFileSync(__dirname + '/aboutpage.html', 'utf-8');

describe('Homepage server', function() {
  describe('GET /about', function() {
    it('returns status code 200', function(done) {
      request.get(base_url+'about', function(err, res, body) {
        expect(res.statusCode).toBe(200);
        done();
      });
    });

    it('returns the aboutpage.html file', function(done) {
      request.get(base_url+'about', function(err, res, body) {
        expect(body).toBe(aboutpg);
        done();
      });
    });

  });
});
Daynil commented 7 years ago

Serving directories with static middleware

Challenge Description

In real world applications, a particular route on your website will often include multiple files. The index.html of that route will often need to reference a styles.css and a scripts.js in order to serve a complex, interactive view. Instead of sending a series of files manually, express provides a way to serve static files as a full directory using static middleware.

Middleware is a function that express can trigger prior to invoking your final request handler. It sits between the raw request sent by the user and the final intended route. Express comes with the static middleware function built in. We can use the static middleware to serve files or entire directories.

app.use(express.static(__dirname + '/staticfiledirectory'));

The static middleware is a very useful tool. For simple static websites, it is sufficient to invoke the static middleware on the directory containing all of your pages and files and let the browser make requests based on that directory's file structure.

Instructions

You have a /public directory containing all the files your website needs with a structure:

public
├─page2
│  └─otherpage.html
├─index.html
├─styles.css

Use the express static middleware to serve your entire webpage.

Seed code

var express = require('express');
var app = express();

// Enter code below this line

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Solution

var express = require('express');
var app = express();

// Enter code below this line

app.use(express.static(__dirname + '/public'));

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Tests

var fs = require('fs');
var request = require('request');
var base_url = 'http://localhost:3000/';
var index = fs.readFileSync(__dirname + '/public/index.html', 'utf-8');
var otherpage = fs.readFileSync(__dirname + '/public/page2/otherpage.html', 'utf-8');
var styles = fs.readFileSync(__dirname + '/public/styles.css', 'utf-8');

describe('Directory server', function() {
  describe('GET /', function() {
    it('returns status code 200', function(done) {
      request.get(base_url, function(err, res, body) {
        expect(res.statusCode).toBe(200);
        done();
      });
    });

    it('returns the index.html file', function(done) {
      request.get(base_url, function(err, res, body) {
        expect(body).toBe(index);
        done();
      });
    });
  });

  describe('GET /page2/otherpage.html', function() {
    it('returns status code 200', function(done) {
      request.get(base_url+'/page2/otherpage.html', function(err, res, body) {
        expect(res.statusCode).toBe(200);
        done();
      });
    });

    it('returns the otherpage.html file', function(done) {
      request.get(base_url+'/page2/otherpage.html', function(err, res, body) {
        expect(body).toBe(otherpage);
        done();
      });
    });
  });

  describe('GET /styles.css', function() {
    it('returns status code 200', function(done) {
      request.get(base_url+'/styles.css', function(err, res, body) {
        expect(res.statusCode).toBe(200);
        done();
      });
    });

    it('returns the otherpage.html file', function(done) {
      request.get(base_url+'/styles.css', function(err, res, body) {
        expect(body).toBe(styles);
        done();
      });
    });
  });
});
Daynil commented 7 years ago

Route Parameters

Challenge Description

Express can process parts of a url as a parameter that you can access. You can designate a portion of your route as a parameter by prefixing it with : and the name of the parameter.

app.get('/name/:user', function(request, response) {
  var clientName = request.params.user;
});

Now, if an application makes a GET request to this route, you can grab a reference to the contents of :user.

Instructions

Create a server that can process GET requests to the route /times42/:number. Requests to this route should respond with the result of the number parameter * 42.

Seed code

var express = require('express');
var app = express();

// Enter code below this line

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Solution

var express = require('express');
var app = express();

app.get('/times42/:number', function(request, response) {
  var clientNumber = request.params.number;
  response.send('' + clientNumber*42);
});

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Tests

var request = require('request');
var base_url = 'http://localhost:3000/times42/';

describe('Hello world server', function() {
  describe('GET /times42/12', function() {
    it('returns correct output', function(done) {
      request.get(base_url+'12', function(err, res, body) {
        expect(body).toBe('504');
        done();
      });
    });
  });
});
Daynil commented 7 years ago

Create an API that sends JSON

Challenge Description

Express makes an excellent API server. You can send JSON to the client using the response.json() method.

response.json({message: 'hello world'});

Instructions

A server's API works with client side AJAX to provide data for the front end. Create a server that responds to GET requests to the route /api/productlist with the product list stored on the server.

Seed code

var express = require('express');
var app = express();
var productList = [
  {
    product: 'shirt',
    price: 19.95,
    quantity: 210
  },
  {
    product: 'pants',
    price: 25.00,
    quanitity: 149
  }
];

// Enter code below this line

// Only change code above this line

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Solution

var express = require('express');
var app = express();
var productList = [
  {
    product: 'shirt',
    price: 19.95,
    quantity: 210
  },
  {
    product: 'pants',
    price: 25.00,
    quanitity: 149
  }
];

app.get('/api/productlist', function(request, response) {
  response.json(productList);
});

app.listen(3000, function() {
    console.log('Serving on port 3000');
});

Tests

var request = require('request');
var base_url = 'http://localhost:3000/api/productlist';
var productlist = [
  {
    product: 'shirt',
    price: 19.95,
    quantity: 210
  },
  {
    product: 'pants',
    price: 25.00,
    quanitity: 149
  }
];

describe('Product list api', function() {
  describe('GET /api/productlist', function() {
    it('returns the product list', function(done) {
      request.get(base_url, function(err, res, body) {
        var parsedBody = JSON.parse(body);
        expect(parsedBody).toEqual(productlist);
        done();
      });
    });
  });
});
Daynil commented 7 years ago

I implemented the tests with jasmine-node but I can always switch them to something else like mocha/chai or simple asserts with node, whatever ends up being most compatible with how we end up getting these challenges running. Hyperdev utilizes a package.json to dynamically install dependencies, so if we do it that way this should work well by making jasmine-node a dependency.

QuincyLarson commented 7 years ago

@Daynil that sounds like a good approach. For these back end challenges, I think just using plain JavaScript assert tests will work fine for now, and we can incorporate fancier libraries once we are farther along.

QuincyLarson commented 7 years ago

@Daynil @ChaituVR @atjonathan great work on designing these challenges so far.

Can we create a comprehensive checklist of the specific topics we want to cover? The more granular, the better. This will help us better prioritize which challenges to design and prevent us from duplicating our efforts.

QuincyLarson commented 7 years ago

@atjonathan while we're replacing expressworks, we should probably go ahead and cover what learnyounode covers as well. I think it's only like 15 challenges long. If we're already in the mindset of teaching express, Node is pretty similar and the two are pretty closely related imho and could be taught in tandem.

ghost commented 7 years ago

@QuincyLarson, yeh I agree.

QuincyLarson commented 7 years ago

@atjonathan OK - great. When you have a moment, could you come up with a list of topics we should cover (or challenge titles)? A good starting point is Learn You Node's sequence (not all of these titles are sufficiently descriptive):

Could you interpret these into proper challenge names and add them to the list of proposed challenges (your original post on this issue?)

alayek commented 7 years ago

Might want to add a challenge on exposing some data as REST API.

Daynil commented 7 years ago
QuincyLarson commented 7 years ago

@Daynil thanks for the list to these markdown files. It's important to note that NodeSchool's challenges often involve multiple steps, and we want for each of our challenges to just involve a single step (or concept applied). So many of these concepts can be spread across multiple challenges.

QuincyLarson commented 7 years ago

@atjonathan @ChaituVR @Daynil we would like for these challenges to be runnable (and completable) on HyperDev.com. My thinking is that could fork a project there and it would have an HTML interface with test results. The challenge is that if they broke the express app, that HTML interface may not render properly. Do you all have any thoughts on how we might achieve this?

ghost commented 7 years ago

@QuincyLarson is there anyway of using the repl api for running challenges and tests in the freecodecamp editor?

cc/ @alayek

QuincyLarson commented 7 years ago

@atjonathan We would only use this for non-JavaScript challenges, as it would be much slower than running them in the camper's browser. I think repl.it eventually plans to support multiple files (node.js), which will be huge if and when it happens. @alayek knows a lot more about repl.it than I do.

ghost commented 7 years ago

@ChaituVR I think we should remove your first challenge, Hello NodeJs. You introduce REPL later on anyway.

alayek commented 7 years ago

One thing - do we introduce campers to the idea that you can use Google Chrome JS debugger to debug Node JS applications? I think we should add that, as being able to put breakpoints in execution path is a great plus.

QuincyLarson commented 7 years ago

Proposed challenges: (https://github.com/FreeCodeCamp/CurriculumExpansion/issues/33)

QuincyLarson commented 7 years ago

@alayek I think showing them how to use the Chrome JS debugger to debug Node JS applications would be better demonstrated in a video challenge.

QuincyLarson commented 7 years ago

Issue merged into https://github.com/FreeCodeCamp/CurriculumExpansion/issues/44