Fueling Curiosity, One Insight at a Time

At Codemancers, we believe every day is an opportunity to grow. This section is where our team shares bite-sized discoveries, technical breakthroughs and fascinating nuggets of wisdom we've stumbled upon in our work.

Sep 26, 2024
How to test an API endpoint.

Lets say we have to test an API endpoint api/projects


describe("POST /api/projects", () => {
    test("redirect with 401 status if the user is not logged in", async () => {
      jest
        .spyOn(nextAuth, "getServerSession")
        .mockImplementation(() => Promise.resolve());

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: projectData,
      });

      const res = await postProjectHandler(req as any);
      expect(res.status).toEqual(401);
    });

    test("return 400 if the request body is invalid", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: {},
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);

      expect(res.status).toEqual(400);
    });

    test("store project in database", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const mockResponse = {
        ok: true,
        team: {
          id: "T08DABCD",
          name: "Prisma",
        },
      };

      const mockList = jest.fn().mockResolvedValue(mockResponse);
      https://slackClient.team.info|slackClient.team.info = mockList;

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: {
          ...projectData,
        },
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);
      const json = await res.json();

      expect(res.status).toEqual(201);
      expect(json.project.name).toEqual("Test name");
      expect(json.project.description).toEqual(
        "Test description"
      );
    });
  });


1. describe: This is a block in Jest used to group related tests together. In our case, it groups tests for the POST /api/projects endpoint. It helps organize tests logically.
2. test: Each test block defines an individual test case. It contains a name (description) of what it’s testing and a function with the test logic. The three tests are:
• User is redirected with a 401 if they are not logged in.
• A 400 status is returned if the request body is invalid.
• The project is stored in the database when valid data is provided.
3. Mocking:
jest.spyOn(): This creates a mock (or "spy") for a specific function. In this case, we are mocking the getServerSession function from nextAuth to control its output (whether the user is logged in or not). This avoids actually calling the real function and allows you to simulate different conditions.
Mock Implementation: With .mockImplementation(), we’re replacing the real function with a custom one. For example, in the first test, Promise.resolve() is returned to simulate a missing session (not logged in).
4. createRequest<APIRequest>(): This is likely a helper function that creates a mock request object for testing. We use this to simulate an HTTP request (like sending a POST request to your /api/projects endpoint). It includes:
method: Specifies that it’s a POST request.
url: The endpoint being tested.
body: The request data sent with the POST request.
5. postProjectHandler(req as any): This function is our handler for the POST /api/projects endpoint. It processes the incoming request (in req), validates the data, and performs actions like saving to the database or returning errors. We’re testing the results of this function.
6. Assertions:
expect(res.status).toEqual(401): This is checking if the response status matches the expected value. For example, in the first test, we expect a 401 status if the user isn’t logged in.
expect(json.project.name).toEqual("Test name"): Here, you're checking if the response JSON contains the correct project name.
#CCT1JMA0Z #promises #C041BBLJ57G #jest #appRouter
amber.srivastava
amber.srivastava
Sep 26, 2024
How to test an API endpoint.

Let's say we have to test an endpoint /api/projects.


describe("POST /api/projects", () => {
    test("redirect with 401 status if the user is not logged in", async () => {
      jest
        .spyOn(nextAuth, "getServerSession")
        .mockImplementation(() => Promise.resolve());

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: projectData,
      });

      const res = await postProjectHandler(req as any);
      expect(res.status).toEqual(401);
    });

    test("return 400 if the request body is invalid", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: {},
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);

      expect(res.status).toEqual(400);
    });

    test("store project in database", async () => {
      jest.spyOn(nextAuth, "getServerSession").mockImplementation(() =>
        Promise.resolve({
          user: {
            id: user.id,
          },
        })
      );

      const mockResponse = {
        ok: true,
        team: {
          id: "T08DABCD",
          name: "Prisma",
        },
      };

      const mockList = jest.fn().mockResolvedValue(mockResponse);
      https://slackClient.team.info|slackClient.team.info = mockList;

      const req = createRequest<APIRequest>({
        method: "POST",
        url: "/api/projects",
        body: {
          ...projectData,
        },
      });

      req.json = jest.fn().mockResolvedValue(req.body);

      const res = await postProjectHandler(req as any);
      const json = await res.json();

      expect(res.status).toEqual(201);
      expect(json.project.name).toEqual("Test name");
      expect(json.project.description).toEqual(
        "Test description"
      );
    });
  });

amber.srivastava
amber.srivastava
Sep 26, 2024
Using the server.table() method in Hapi.js we can retrieve all the registered routes in a server instance. It returns an array of route groups, containing details like the HTTP method, path, settings and other relevant information.
#hapi.js #server
ashwanikumarjha
Ashwani Kumar Jha
Senior System Analyst
Sep 25, 2024
Sending Body Data as json:
The json function in the request is simulating the body of the request. In a real-world scenario, when you send a request with data (like when you're submitting a form or sending some payload), it is typically part of the body of the HTTP request.
In your test case:


json: async () => ({
  standupData,
}),


This simulates the request body. Since you're testing a PATCH method (which is often used to update resources), the server expects some data to update the resource. This json function acts like a mock for what would be req.body in a real request. In your API handler, you'd probably be extracting the body data using something like:


const data = await req.json();


Thus, the test needs to mock this body data to simulate a real request. It's done asynchronously here because in actual implementations, reading the body data is often asynchronous (e.g., when streaming).
Passing Context (with params):
The context object typically holds parameters that are passed via the route in a Next.js API request, especially when using dynamic routes (e.g., /api/standups/[id]/toggle-status). In Next.js, when you define a dynamic API route like /api/standups/[id]/toggle-status, the id is part of the route path, and Next.js passes it in the context.params object.
In your test case:


const context = {
  params: {
    id: standup.id,
  },
};


You're simulating the dynamic parameter id as part of the request. This is necessary because your API handler likely expects id to come from the route context (not just from the query string or body). In the handler, you're accessing context.params.id:


const { id } = context.params as { id: string };


This allows your API handler to know which standup you're targeting for the update.
#app-router #dynamic-routes #json
aman.suhag
Aman Suhag
System Analyst
Sep 25, 2024
The dig method in Ruby is used to safely extract nested values from arrays or hashes. It allows us to traverse a data structure without worrying about whether each level of the structure exists, thus avoiding NoMethodError exceptions that occur when trying to call methods on nil.

Syntax:


hash_or_array.dig(*keys)


Example:


data = {
  user: {
    profile: {
      name: "John",
      age: 30
    }
  }
}

name = data.dig(:user, :profile, :name) # => "John"


#ruby #CU6U0R822
syedsibtain
Syed Sibtain
System Analyst
Sep 13, 2024
### PostgreSQL's Foreign Data Wrapper (FDW)

PostgreSQL's Foreign Data Wrapper (FDW) extension and its capabilities for accessing remote databases. FDW provides a standard method for connecting to and querying tables in different databases as if they were part of the local database. This feature is particularly useful for integrating data across multiple PostgreSQL instances or accessing data from different servers.

#### What is FDW?

Foreign Data Wrapper (FDW) is an extension in PostgreSQL designed to connect to external data sources. With FDW, users can perform operations on remote tables seamlessly, making it easier to integrate and analyze data across various systems.

#### How to Use FDW

Here's a concise guide on setting up and using FDW:

1. Install the FDW Extension:
To enable FDW, the extension must be installed in the PostgreSQL database:



sql
   CREATE EXTENSION IF NOT EXISTS postgres_fdw;
   



2. Create a Foreign Server:
Define the remote database connection details, including the host, port, and database name:



sql
   CREATE SERVER my_foreign_server
   FOREIGN DATA WRAPPER postgres_fdw
   OPTIONS (host 'your_host', port '5432', dbname 'remote_db');
   



3. Set Up User Mapping:
Configure authentication details for accessing the remote server:



sql
   CREATE USER MAPPING FOR local_user
   SERVER my_foreign_server
   OPTIONS (user 'remote_user', password 'remote_password');
   



4. Create Foreign Tables:
Define tables in the local database that map to the remote database tables:



sql
   CREATE FOREIGN TABLE foreign_table_name (
       column1 datatype,
       column2 datatype
       -- other columns
   )
   SERVER my_foreign_server
   OPTIONS (schema_name 'public', table_name 'remote_table');
   



5. Query the Foreign Tables:
Query the foreign tables as if they were local tables:



sql
   SELECT * FROM foreign_table_name;
   



#### Example Use Case

For instance, if there are two databases on the same PostgreSQL server—sales_db and hr_db—FDW can be used to access employee data from hr_db while working within sales_db. This setup simplifies data integration and reporting across different databases.

FDW streamlines data access and management, providing a powerful tool for integrating and analyzing data from multiple sources within PostgreSQL.

#postgres #database #fdw
vaibhav.yadav
Vaibhav Yadav
Senior System Analyst
Sep 12, 2024
To make your Django application ASGI-compatible and run it with Daphne, follow these steps:

1. Install Daphne: Install Daphne if you haven't already:



   pip install daphne


2. Ensure ASGI Configuration: Your asgi.py file should look like this:



   import os
   from django.core.asgi import get_asgi_application

   os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings')

   application = get_asgi_application()


3. Update settings.py: Add the ASGI_APPLICATION setting to point to your ASGI application:



ASGI_APPLICATION = 'your_project_name.asgi.application'


Replace 'your_project_name.settings' with the path to your Django settings module.

4. Run Daphne: Start Daphne with your ASGI application using:



   daphne -u your_project_name.asgi:application


Alternatively, run it on a specific port:



   daphne -p 8000 your_project_name.asgi:application


This setup will get your Django application running with Daphne as the ASGI server.

#python #django #daphne
adithya.hebbar
Adithya Hebbar
System Analyst
Sep 12, 2024
A Lambda layer in AWS Lambda is a feature that lets us manage and share common code and libraries across multiple Lambda functions. By creating a Lambda layer, we can package common code in its own module, which can then be used by our Lambda functions. This reduces duplication and simplifies the management of shared code.
ashwanikumarjha
Ashwani Kumar Jha
Senior System Analyst
Sep 10, 2024
We can generate a base64-encoded random key easily using either openssl or a combination of dd and base64. Here's how:



openssl rand -base64 32


Alternatively, using dd and base64:



dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64


Both commands will give you a 32-byte random key encoded in base64.

#encryption #openssl
adithya.hebbar
Adithya Hebbar
System Analyst
Aug 28, 2024
To rename a table in TypeORM, follow these steps:

Create a new migration.


npx typeorm migration:create -n RenameTable


This will create a new migration file in the migrations directory

Edit the Migration File:


import { MigrationInterface, QueryRunner } from "typeorm";

export class RenameTable1724826351040 implements MigrationInterface {

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.renameTable('old_table_name', 'new_table_name');

    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.renameTable('new_table_name', 'old_table_name');
    }

}


Run the migration:


npm run typeorm -- migration:run


#typeorm #js
adithya.hebbar
Adithya Hebbar
System Analyst

Showing 13 to 15 of 79 results

Ready to Build Something Amazing?

Codemancers can bring your vision to life and help you achieve your goals