a03 Make an API

DUE: 2022-02-25T00:00:00-5:00

GitHub Classroom Assignment Invite: https://classroom.github.com/a/cyXk13b7

Issues: https://github.com/comp426-2022-spring/a03/issues

Creating a API

In this assignment, you are going to convert the functions that you wrote for a02 to emulate a simple random coin flip and then do things with the resulting information. The focus of the assignment is not necessarily on creating basic API endpoints in Node using Express.js.

The instructions for this are very sparse because I want you to be creative in how you approach this. There are a only a few things that you will have to do very specifically in order to make this work, but beyond that, HOW you do this is really up to you.

List of requirements for submission

  1. server.js file that takes an arbitrary port number as a command line argument (i.e. I should be able to run it with node server.js. The port should default to 5000 if no argument is given.
  2. Default API endpoint that returns 404 Not found for any endpoints that are not defined.
  3. Check endpoint at /app/ that returns 200 OK.
  4. Endpoint /app/flip/ that returns JSON {"flip":"heads"} or {"flip":"tails"} corresponding to the results of the random coin flip.
  5. Endpoint /app/flips/:number that returns JSON including an array of the raw random flips and a summary. Example below.
  6. Endpoint /app/flip/call/heads that returns the result of a random flip match against heads as JSON.
  7. Endpoint /app/flip/call/tails that returns the result of a random flip match against tails as JSON.
  8. ALL endpoints should return HTTP headers including a status code and the appropriate content type for the response.
  9. All of this should be in a Node package with "main" set to server.js.
  10. The test script defined in package.json should be set to "node server.js --port=5555"

Examples

If I run the following curl commands against your API, I should see output corresponding to what is shown here in STDOUT.

PLEASE USE CURL to test your endpoints as below RATHER THAN relying on the autograder to tell you what is wrong. You must become accustomed to testing your own scripts.

$ curl http://localhost:5000/app/
200 OK
$ curl -I http://localhost:5000/app/
i=HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain
Date: Tue, 15 Feb 2022 18:02:32 GMT
Connection: keep-alive
Keep-Alive: timeout=5
$ curl http://localhost:5000/app/flip/
{"flip":"tails"}
$ curl -I http://localhost:5000/app/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/json; charset=utf-8
Content-Length: 16
ETag: W/"10-VYm8Bk1/RW8RGhDXdTwBYk6lbGE"
Date: Tue, 15 Feb 2022 18:06:17 GMT
Connection: keep-alive
Keep-Alive: timeout=5
$ curl http://localhost:5000/app/flips/20
{"raw":["tails","tails","heads","tails","tails","tails","heads","heads","tails","tails","heads","heads","tails","heads","tails","heads","tails","heads","tails","heads"],"summary":{"tails":11,"heads":9}}
$ curl http://localhost:5000/app/flip/call/heads
{"call":"heads","flip":"heads","result":"win"}
$ curl http://localhost:5000/app/flip/call/tails
{"call":"tails","flip":"heads","result":"lose"}
$ curl http://localhost:5000/app/some/nonexistent/endpoint/
404 NOT FOUND

Set up your environment

You will need to run npm init like usual and make sure that you make changes according to the list above.

Once you have initialized your repo as a Node package, you need to install express. If you are using minimist or yargs or some other package to handle command line arguments, then you need to also install that, e.g.:

$ npm install express minimist

Require dependencies

Once you have initialized your repository, you will need to create your script file, server.js and add a few things to get going with express. The first is requiring whatever dependencies you need (including express).

1
2
3
// Require Express.js
const express = require('express')
const app = express()

Start app server

Replace “HTTP_PORT” below with whatever you are using as your port variable. Alternatively, assign “HTTP_PORT” as your port variable.

1
2
3
4
// Start an app server
const server = app.listen(HTTP_PORT, () => {
    console.log('App listening on port %PORT%'.replace('%PORT%',HTTP_PORT))
});

Define default endpoint

1
2
3
4
// Default response for any other request
app.use(function(req, res){
    res.status(404).send('404 NOT FOUND')
});

Define check endpoint

app.get('/app/', (req, res) => {
// Respond with status 200
	res.statusCode = 200;
// Respond with status message "OK"
    res.statusMessage = 'OK';
    res.writeHead( res.statusCode, { 'Content-Type' : 'text/plain' });
    res.end(res.statusCode+ ' ' +res.statusMessage)
});

Note the similarities and differences between the above default and check endpoints.

Fill in the blank lines after the comments. in the check endpoint.

Response and request

You should note that any variable inside your endpoint definitions that have res are properties of the response object from Express (which is an extension of Node’s http.ServerResponse class. You can use response properties from that as well. Much of what Express does is redefine them to be shorter and chainable as in the case of the status code examples above.

Some other response properties you can use are:

  • res.json() responds with whatever JSON is contained within it.
  • res.send() responds in plaintext with any message contained therein.
  • res.setHeader() sets one of the HTTP header parameters, like Content-Type.

The full documentation for Express’s response object is here: https://expressjs.com/en/5x/api.html#res

The request object is also available and you can treat these just like any variable.

For this assignment you will specifically need req.params to get the number from the URL for your multiple flips endpoint.

That endpoint definition will look like this:

app.get('/app/flips/:number', (req, res) => {
	//Some
	//expressions
	//go
	//here
});

In the endpoint definition where you see :number, the colon makes that part of the definition into a parameter, which is variable. In this case, you will be using a number.

You can get this parameter by referring to req.params.number.

You can use whatever you want for this definition. The names of parameters are arbitrary.

In this case, you might use something like this to pass that parameter to your coin-flipping function.

app.get('/app/flips/:number', (req, res) => {
	const flips = manyflips(req.params.number)
	//Other
	//expressions
	//go
	//here
});

In the example above, req.params.number can be passed to whatever function we are using to generate a bunch of coin flips.

The full documentation for Express’s request object is here: https://expressjs.com/en/5x/api.html#req

Functions

You should already have a bunch of coin flip functions from a02 that you can adapt to use in this server script.

You can put them in however you like. You can include them in the server file itself. You can make them into a module. Whatever works for you is fine as long as the endpoints return the appropriate output.

Good luck!

We will be going over parts of this assignment and expanding upon them over the next few weeks in class, so if you are having trouble getting something to work: don’t worry. We will likely cover in class at some point soon.

Also, be sure to refer to what you have done in previous assignments. These assignments build on one another, so try to carry things over, when appropriate, as you are looking for solutions.