📚 Tutorial🕸️ Express JsBasic - Data method

Data method

The following guild will shows how to recived data from API with Params, Query and Body.

Params

The params is a MUST type in data method in order to active the regarding API.

Single Params

[GET] http://localhost:8080/api/13
// Single params
app.get("/api/:id", function (req: Request, res: Response) {
    const { id } = req.params; // 13
    res.json({ data: id });
});

Multi params

[GET] http://localhost:8080/api/13/peter
// Single params
app.get("/api/:id/:name", function (req: Request, res: Response) {
    const { id, name } = req.params; // 13, peter
    res.json({ data: id, name: name });
});

Query

The query is a OPTIONALS type in data method, means you can still access the regarding API without input any query.

Single Query

[GET] http://localhost:8080/api?id=14
// Single query
app.get("/api", function (req: Request, res: Response) {
    const { id } = req.query; // 14
    res.json({ data: id });
});

Multi Query

[GET] http://localhost:8080/api?id=14&name=tom
// Single query
app.get("/api", function (req: Request, res: Response) {
    const { id, name } = req.query; // 14, tom
    res.json({ data: id, name: name });
});

Different between params and Query

As the top said, let’s see the different of a params and Query API.

params
app.get("/api/:id", function (req: Request, res: Response) {
    const { id } = req.params; // 13
    res.json({ data: id });
});
params responds
- Normal ways ⭕
[GET] http://localhost:8080/api/13
Respond: { data: 13 }
 
- No params cases ⛔
[GET] http://localhost:8080/api
Respond: 404 Route not found
query
app.get("/api", function (req: Request, res: Response) {
    const { id } = req.query;
    res.json({ data: id });
});
query responds
// Normal ways ⭕
// [GET] http://localhost:8080/api?id=80
// Respond: { data: 80 }
 
// No query cases ⭕
// [GET] http://localhost:8080/api
// Respond: { data: null }

In query, the API still accessable without inputing ID. Means if you require your user to input stuff, we better suggest to use params compare to query.

:::tip

Yet, you can still set up constraints to require user input query in API logics or using other checking libraries / packages like zod, yum, express-validator or others.

:::

Body

Body is a method to recive HTML data like <forms> or body in fetch.

Json data

In default, we have to added express.json() and express.urlencoded({ extended: true }) to let expressjs for parse body data.

server.ts
// Add these line to your server
app.use(express.json()); // for parsing application/json
app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
[POST] http://localhost:8080/api
app.post('/api', function (req, res) {
    console.log(req.body);
    res.json({ 
        status: true,
        data: req.body.id,
        name: req.body.name
    });
});
frontend.js
const res = await fetch( "http://localhost:8080/api" ,{
    method:"POST",
    headers:{ 
        // Authorization: `Bearer ${token}`,
        "Content-Type":"application/json"
    },
    body: JSON.stringify({
        id: 10,
        name: "Peter"
    });
});
 
const result = await res.json();
console.log(result);
/*
    status: true,
    data: 10,
    name: "Peter"
*/

multipart/form-data

With formidable
https://www.npmjs.com/package/formidable#readme

formidable.ts
import path from "path"
import fs from "fs"
import formidable, { Fields, Files } from "formidable";
import IncomingForm from "formidable/Formidable";
import { Request } from "express"
 
// Create a folder if not exist
const uploadDir = "uploads"
const finalDir = path.join(__dirname, "..", uploadDir)
if (!fs.existsSync(finalDir)) {
    fs.mkdirSync(finalDir)
}
 
export const form = formidable({ 
    multiples: true,
    uploadDir: finalDir,
    keepExtensions: true,
    maxFileSize: 1024 * 1024 * 20, // (20mb)
    maxFiles: 1,
    filter: part => part.mimetype?.startsWith('image/') || false,
    filename: (originalName, originalExt, part, form) => {
        const ext = part.mimetype?.split("/").pop();
        return `${part.name}-${Date.now()}.${ext}`;
    },
});
 
export function formParse(form: IncomingForm, req: Request) {
    return new Promise<{ fields: Fields; files: Files }>((resolve, reject) => {
      form.parse(req, (err, fields, files) => {
        if (err) {
          reject(err);
        } 
        resolve({ fields, files });
      });
    });
}
server.ts
import { formParse } from "formidable"
 
// [POST] http://localhost:8080/data
app.post('/data', async (req: express.Request, res: express.Response) => {
  try{
    const data = await formParse(form, req);
    
    return res.status(200).json({ 
        status: true,
        bodyData:  data.fields, // data.fields : The original form data (No Files)
        filesData: data.files   // data.files : The media file data from form (Files)
    })
  }
  catch(err:any){
    return res.status(200).json({ status: false })
  }  
});
frontend.js
const formData = new FormData();
 
formData.append("name", "Peter");
 
const res = await fetch( "http://localhost:8080/data" ,{
    method:"POST",
    body: formData
});
 
const result = await res.json();