NodeJS #3
Basic practice
$ whoami
Inna Ivashchuk
Senior Software Engineer
JS developer, music fan, movie-dependent and Star Wars fan 🤓
May the Force be with you!
Agenda
-
HTTP methods, headers, and status codes
-
REST API
-
http module
-
Command-line arguments. Environment variables
-
Let’s create a REST API
HTTP methods, headers and status codes
HTTP
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.
How HTTP works
How HTTP works
HTTP methods
GET
POST
OPTIONS
PATCH
DELETE
PUT
TRACE
HEAD
CONNECT
HTTP methods
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 header
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.
HTTP headers
Authentication
Cookies
CORS
Caching
Proxies
Security
Redirects
HTTP header types
Headers can be grouped according to their contexts:
- Request headers contain more information about the resource to be fetched, or about the client requesting the resource.
- Response headers hold additional information about the response, like its location or about the server providing it.
- Representation headers contain information about the body of the resource, like its MIME type, or encoding/compression applied.
- Payload headers contain representation-independent information about payload data, including content length and the encoding used for transport.
HTTP header types
Headers can also be grouped according to how proxies handle them:
The most common response codes
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
Headers: Content-Type
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.
Headers: Content-Type
MIME types:
- application (application/zip , application/javascript an etc)
- audio (audio/mpeg, audio/vorbis)
- font (font/woff, font/ttf, and font/otf)
- image (image/jpeg, image/png, and image/svg+xml)
- text (text/plain, text/csv, and text/html)
- video (video/mp4)
REST API
App 2
API
App 3
App 1
App 4
Standard situation
What is REST API?
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
Architectural constraints
In order for an API to be considered RESTful, it has to conform to six criteria:
- A client-server architecture
- Stateless client-server communication,
- Cacheable data that streamlines client-server interactions.
- A uniform interface between components so that information is transferred in a standard form.
- A layered system that organizes each type of server (those responsible for security, load-balancing, etc.) involved the retrieval of requested information into hierarchies, invisible to the client.
- Code-on-demand (optional): the ability to send executable code from the server to the client when requested, extending client functionality.
Applied to web services
Web service APIs that adhere to the REST architectural constraints are called RESTful APIs. HTTP-based RESTful APIs are defined with the following aspects:
- a base URI, such as http://api.example.com/;
- standard HTTP methods (e.g., GET, POST, PUT, and DELETE);
- a media type that defines state transition data elements (e.g., Atom, microformats, application/vnd.collection+json,:91–99 etc.).
The semantics of HTTP methods
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
The anatomy of a Request
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)
Endpoints or routes
- https://api.github.com/users (fetch all users)
- https://api.github.com/users/1 (fetch one user by ID)
- https://api.github.com/users?per_page=5 (fecth first 5 users)
GET
- https://api.github.com/users (create a user with provided data)
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
}
Endpoints or routes
PATCH / PUT
- https://api.github.com/users/1 (delete a user by ID)
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
}
- https://api.github.com/users/1 (update a user by ID with provided data)
cURL
GET
curl -X GET \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
https://jsonplaceholder.typicode.com/posts/1
- https://api.github.com/users/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.
cURL
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
- https://jsonplaceholder.typicode.com/posts
http module
http module
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 =)
});
});
Create a server
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.
Method, URL and Headers
const { method, url, headers } = request;
const userAgent = headers['user-agent'];
if (url === '/login') {
// redirect to login
}
The request object is an instance of IncomingMessage.
Request Body
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.
HTTP Status Code
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.
HTTP Status Code
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.
Setting Response Headers
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'
});
Sending Response Body
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>');
A Quick Thing About Errors
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.
Command-line arguments. Environment variables
What is an environment variable?
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
.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"
How to read environment variables from Node.js
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
How to read environment variables from Node.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.
How to read environment .env file
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.
How to read environment .env file
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.
Accept arguments from the command line
node app.js joe
Arguments can be standalone or have a key and a value.
For example:
or:
node app.js name=joe
Accept arguments from the command line
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
Postman and Swagger
Swagger
Postman
Let’s create a REST API
What should be implemented
-
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"
Q & A
Homework
-
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
NodeJS Core #3
By Inna Ivashchuk
NodeJS Core #3
- 421