Basic practice
Inna Ivashchuk
Senior Software Engineer
JS developer, music fan, movie-dependent and Star Wars fan 🤓
May the Force be with you!
HTTP methods, headers, and status codes
REST API
http module
Command-line arguments. Environment variables
Let’s create a REST API
Hypertext Transfer Protocol (HTTP) is an application-layer protocol for transmitting hypermedia documents, such as HTML. It was designed for communication between web browsers and web servers, but it can also be used for other purposes. HTTP follows a classical client-server model, with a client opening a connection to make a request, then waiting until it receives a response. HTTP is a stateless protocol, meaning that the server does not keep any data (state) between two requests.
GET
POST
OPTIONS
PATCH
DELETE
PUT
TRACE
HEAD
CONNECT
GET | Get a representation of the target resource’s state. |
---|---|
GET | Requests a representation of the specified resource. Requests using GET should only retrieve data. |
HEAD | Asks for a response identical to that of a GET request, but without the response body. |
POST | Used to submit an entity to the specified resource, often causing a change in state or side effects on the server. |
PUT | Replaces all current representations of the target resource with the request payload. |
DELETE | Deletes the specified resource. |
CONNECT | Establishes a tunnel to the server identified by the target resource. |
OPTIONS | Used to describe the communication options for the target resource. |
TRACE | Performs a message loop-back test along the path to the target resource (for proxy-debugging purposes) |
PATCH | Used to apply partial modifications to a resource. |
Description
HTTP methods
HTTP headers let the client and the server pass additional information with an HTTP request or response. An HTTP header consists of its case-insensitive name followed by a colon (:), then by its value. Whitespace before the value is ignored.
Authentication
Cookies
CORS
Caching
Proxies
Security
Redirects
Headers can be grouped according to their contexts:
Headers can also be grouped according to how proxies handle them:
408
Request Timeout
200
OK
301
Moved Permanently
401
Unauthorized
403
Forbidden
404
Not Found
429
Too Many Requests
409
Conflict
500
Internal Server Error
The Content-Type representation header is used to indicate the original media type of the resource (prior to any content encoding applied for sending).
In responses, a Content-Type header tells the client what the content type of the returned content actually is. Browsers will do MIME sniffing in some cases and will not necessarily follow the value of this header; to prevent this behavior, the header X-Content-Type-Options can be set to nosniff.
In requests, (such as POST or PUT), the client tells the server what type of data is actually sent.
MIME types:
App 2
API
App 3
App 1
App 4
A REST API (also known as RESTful API) is an application programming interface (API or web API) that conforms to the constraints of REST architectural style and allows for interaction with RESTful web services. REST stands for representational state transfer and was created by computer scientist Roy Fielding.
Client
Database
GET, POST, PUT, PATCH, DELETE
REST API Model
JSON data
REST API
In order for an API to be considered RESTful, it has to conform to six criteria:
Web service APIs that adhere to the REST architectural constraints are called RESTful APIs. HTTP-based RESTful APIs are defined with the following aspects:
The following table shows how HTTP methods are intended to be used in HTTP APIs, including RESTful ones.
GET | Get a representation of the target resource’s state. |
---|---|
GET | Used to get a resource from a server. The server looks for the data you requested and sends it back to you. A GET request performs a READ operation |
POST | Used to create a new resource on a server. On a POST request, the server creates a new entry in the database and tells you whether the creation is successful. POST request performs a CREATE operation. |
PUT / PATCH | These two requests are used to update a resource on a server. Using such requests the server updates an entry in the database and tells you whether the update is successful. PUT or PATCH request performs an UPDATE operation. |
DELETE | Used to delete a resource from a server. On a DELETE request, the server deletes an entry in the database and tells you whether the deletion is successful. |
Description
HTTP methods
It’s important to know that a request is made up of four things:
The endpoint (or route)
The methods
The headers
The data (or body)
GET
POST
{
login: "mojombo",
// id should be created
node_id: "MDQ6VXNlcjE=",
avatar_url: "https://avatars.githubusercontent.com/u/1?v=4",
gravatar_id: "",
url: "https://api.github.com/users/mojombo",
....
type: "User",
site_admin: false
}
PATCH / PUT
DELETE
{
login: "mojombo",
id: 1,
node_id: "MDQ6VXNlcjE=",
avatar_url: "https://avatars.githubusercontent.com/u/1?v=4",
gravatar_id: "",
url: "https://api.github.com/users/mojombo",
....
type: "User",
site_admin: false
}
GET
curl -X GET \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
https://jsonplaceholder.typicode.com/posts/1
cURL is a computer software project providing a library and command-line tool for transferring data using various network protocols. The name stands for "Client URL", which was first released in 1997.
POST
curl -X POST \
-H "Content-Type: application/json; charset=UTF-8" \
-d '{"title": "The best actor", "body": "Keanu Reeves", "userId": 1}' \
https://jsonplaceholder.typicode.com/posts
To use the HTTP server and client one must require('http').
The HTTP interfaces in Node.js are designed to support many features of the protocol which have been traditionally difficult to use. In particular, large, possibly chunk-encoded, messages. The interface is careful to never buffer entire requests or responses, so the user is able to stream data.
const http = require('http');
// request from the server to an API
http.get('http://localhost:3000/api/users', { agent }, (res) => {
res.on('data', (data) => {
// Do nothing or do something =)
});
});
const http = require('http');
const server = http.createServer((request, response) => {
// magic happens here!
});
server.on('request', (request, response) => {
// the same kind of magic happens here!
})
Any node web server application will at some point have to create a web server object. This is done by using createServer.
The function that's passed into createServer is called once for every HTTP request that's made against that server, so it's called the request handler.
The Server object returned by createServer is an EventEmitter.
const { method, url, headers } = request;
const userAgent = headers['user-agent'];
if (url === '/login') {
// redirect to login
}
The request object is an instance of IncomingMessage.
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// at this point, `body` has the entire
// request body stored in it as a string
});
When receiving a POST or PUT request, the request body is important to your application. The request object that's passed into a handler implements the ReadableStream interface.
The chunk emitted in each 'data' event is a Buffer.
const http = require('http');
const server = http.createServer((request, response) => {
// set correct status code
response.statusCode = 404;
// magic happens here!
});
If you don't bother setting it, the HTTP status code on a response will always be 200.
const http = require('http');
const server = http.createServer((request, response) => {
// set correct status code
response.statusCode = 404;
// magic happens here!
});
If you don't bother setting it, the HTTP status code on a response will always be 200.
response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');
Headers are set through a convenient method called setHeader.
We can explicitly write the headers to the response stream. To do this, there's a method called writeHead, which writes the status code and the headers to the stream.
response.writeHead(200, {
'Content-Type': 'application/json',
'X-Powered-By': 'bacon'
});
response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();
Since the response object is a WritableStream, writing a response body out to the client is just a matter of using the usual stream methods.
Or to send as the last bit of data on the stream:
response.end('<html><body><h1>Hello, World!</h1></body></html>');
request.on('error', (err) => {
// This prints the error message and stack trace to `stderr`.
console.error(err.stack);
});
Since the request object is a ReadableStream, it's also an EventEmitter and behaves like one when an error happens.
Note: If we don't have a listener for that event, the error will be thrown, which could crash your Node.js program.
An environment variable is a dynamic-named value that can affect the way running processes will behave on a computer. They are part of the environment in which a process runs.
.env file can be used to store needed environment variables. A . env file or dotenv file is a simple text configuration file for controlling your Applications's environment constants.
# .env file
APP_NAME="restfull-api"
NODE_ENV="development"
PORT="3000"
HOST="127.0.0.1"
The process core module of Node.js provides the env property which hosts all the environment variables that were set at the moment the process was started.
The below code runs app.js and set NODE_ENV and APP_NAME.
NODE_ENV=development APP_NAME=foobar node app.js
function() {
const mode = process.env.NODE_ENV;
const appName = process.env.APP_NAME;
console.log({ mode, appName });
}
To access environment variable in JS file:
In the same way, we can access any custom env. variables.
APP_NAME="restfull-api"
NODE_ENV="development"
PORT="3000"
HOST="127.0.0.1"
If you have multiple environment variables in your node project, you can also create an .env file in the root directory of your project, and then use the dotenv package to load them during runtime.
const env = require('dotenv').config();
function app() {
console.log({ env });
console.log('parsed env PORT: ', env.parsed.PORT);
}
app();
As we are using dotenv package in our JS files and it will look like:
We can also run our js file with node -r dotenv/config app.js command if we don't want to import the package in your code.
node app.js joe
Arguments can be standalone or have a key and a value.
For example:
or:
node app.js name=joe
node app.js joe
From the process object, built into Node.js, it exposes an argv property, which is an array that contains all the command line invocation arguments.
If we have one argument without an index name, like this:
// can iterate over all the arguments
process.argv.forEach((val, index) => {
console.log(`${index}: ${val}`)
});
const args = process.argv.slice(2)
args[0]
we can access it using
RESTfull API
Several different endpoints (routes) to interact with API
The server should serve static files (index.html, main.js, and main.css) using a non-blocking IO approach - "fs/promises"
Create a new directory tutorial3
Create API, that follows architecture constraints of REST API
Create different endpoints to interact with API
Create static files (index.html, main.js, and main.css)
Server static on '/' route