Magento 2 TypeScript Express API and GraphQL using NodeJento

This setup will include TypeScript, Express, GraphQL(Apollo Server), and NodeJento as the ORM layer for Adobe Commerce

Yegor Shytikov
7 min readNov 5, 2024

Magento 2 Requirements.

1. Node.js (v14 or higher)

2. TypeScript installed globally or as a dev dependency.

3. NodeJento Sequelize based magento MySQL ORM.

4. NodeJS Appolo Server Graph QL library

5. Magento Open Source, Mage OS(fork), or Adobe Commerce installation

6. ExpressJS and other libs.

1. Set Up Your Magento 2 NodeJS Project

Create a new directory for your project and initialize it:

mkdir nodejento-api
cd nodejento-api
npm init -y

2. Install Dependencies

Install the required dependencies:

# Core dependencies
npm install express sequelize mysql2
# nodejento from the github

# TypeScript and type definitions
npm install – save-dev typescript @types/node @types/express @types/sequelize ts-node

3. Initialize TypeScript

Generate a tsconfig.json file to configure TypeScript:

npx tsc  – init

4. Set Up Project Structure

Create the following directory structure:

nodejento-api/
├── src/
│. ├── config/
│. │. └── database.ts
│. ├── controllers/
│. │. └── productController.ts
│. ├── models/
│. │. └── product.ts
│. ├── routes/
│. │. └── productRoutes.ts
│. ├── app.ts
│. └── server.ts
├── tsconfig.json
└── package.json

5. Configure the Database Connection

In src/config/database.ts, configure NodeJento to connect to the Magento 2 database:

import { Sequelize } from ‘sequelize’;

// Define the connection settings (modify according to your Magento DB)
const sequelize = new Sequelize('magento_db', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
logging: false, // Disable SQL logging
});

export default sequelize;

6. Define the Sequelize Model or use NodeJento

In src/models/product.ts, define a model for the Magento product table using Sequelize:

module.exports = function(sequelize, DataTypes) {
return sequelize.define('Product', {
entity_id: {
autoIncrement: true,
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
comment: "Entity ID"
},
attribute_set_id: {
type: DataTypes.SMALLINT.UNSIGNED,
allowNull: false,
defaultValue: 0,
comment: "Attribute Set ID"
},
type_id: {
type: DataTypes.STRING(32),
allowNull: false,
defaultValue: "simple",
comment: "Type ID"
},
sku: {
type: DataTypes.STRING(64),
allowNull: true,
comment: "SKU"
},
has_options: {
type: DataTypes.SMALLINT,
allowNull: false,
defaultValue: 0,
comment: "Has Options"
},
required_options: {
type: DataTypes.SMALLINT.UNSIGNED,
allowNull: false,
defaultValue: 0,
comment: "Required Options"
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.Sequelize.fn('current_timestamp'),
comment: "Creation Time"
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.Sequelize.fn('current_timestamp'),
comment: "Update Time"
}
}, {
sequelize,
tableName: 'catalog_product_entity',
hasTrigger: true,
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "entity_id" },
]
},
{
name: "CATALOG_PRODUCT_ENTITY_ATTRIBUTE_SET_ID",
using: "BTREE",
fields: [
{ name: "attribute_set_id" },
]
},
{
name: "CATALOG_PRODUCT_ENTITY_SKU",
using: "BTREE",
fields: [
{ name: "sku" },
]
},
]
});
};

or just use NodeJento:

7. Create the Product Express Controller

In src/controllers/productController.ts, create a controller to handle API requests:

import { Request, Response } from 'express';
import Product from '../models/product';

export const getProducts = async (req: Request, res: Response) => {
try {
const products = await Product.findAll();
res.json(products);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch products' });
}
};

export const getProductById = async (req: Request, res: Response) => {
try {
const product = await Product.findByPk(req.params.id);
if (product) {
res.json(product);
} else {
res.status(404).json({ error: 'Product not found' });
}
} catch (error) {
res.status(500).json({ error: 'Failed to fetch product' });
}
};

8. Set Up the Routes

In src/routes/productRoutes.ts, define routes to handle API endpoints for products:

import { Router } from 'express';
import { getProducts, getProductById } from '../controllers/productController';

const router = Router();

router.get('/products', getProducts);
router.get('/products/:id', getProductById);

export default router;

9. Configure Express App

In src/app.ts, set up the Express app:

import express, { Application } from 'express';
import productRoutes from './routes/productRoutes';

const app: Application = express();
app.use(express.json());
app.use('/api', productRoutes);

export default app;

10. Set Up the Server

In src/server.ts, start the server:

import app from './app';
import sequelize from './config/database';

const PORT = process.env.PORT || 5000;

sequelize
.authenticate()
.then(() => {
console.log('Database connected');
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
})
.catch((error) => {
console.error('Unable to connect to the database:', error);
});

11. Update tsconfig.json for TypeScript

Make sure your tsconfig.json includes src in the “include” field:

{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}

12. Run the API

To run the API, use the following commands:

npx tsc # Compiles TypeScript to JavaScript in the `dist` folder
node dist/server.js

Alternatively, to run directly with ts-node during development:

npx ts-node src/server.ts

13. Test the API

With the server running, you can test the API endpoints:

# GET /api/products: Fetches all products

# GET /api/products/:id: Fetches a product by ID

Example Request with curl

curl http://localhost:5000/api/products
curl http://localhost:5000/api/products/1

You now have a basic TypeScript-based Express API using NodeJento (powered by Sequelize ORM) to directly interact with the Magento database without using magento PHP. This API can be extended further based on your project needs.

Magento 2 Express Graph QL

To create a GraphQL API using TypeScript and NodeJento you need Apollo Server (for GraphQL), and NodeJento Sequelize (ORM) to handle the Magento database through NodeJS.

14. You will need to add apollo-server-express:

npm install express apollo-server-express

Modify directory structure by adding graphql/schema.ts and resolvers.ts

nodejento-graphql-api/
├── src/
│. ├── config/
│. │. └── database.ts
│. ├── models/
│. │. └── product.ts
│. ├── graphql/
│. │. ├── schema.ts
│. │. └── resolvers.ts
│. ├── app.ts
│. └── server.ts
├── tsconfig.json
└── package.json

15. Define the GraphQL Schema

In src/graphql/schema.ts, define your GraphQL schema:

import { gql } from 'apollo-server-express';

const typeDefs = gql`
type Product {
id: Int!
sku: String!
name: String!
price: Float!
}

type Query {
products: [Product]
product(id: Int!): Product
}
`;
export default typeDefs;

16. Create the Resolvers for Magento

In src/graphql/resolvers.ts, create resolvers to handle GraphQL queries:

import Product from '../models/product';

const resolvers = {
Query: {
products: async () => {
return await Product.findAll();
},
product: async (_: any, args: { id: number }) => {
return await Product.findByPk(args.id);
},
},
};

export default resolvers;

17. Modify Express to use Apollo Server

In src/app.ts, set up the Express and Apollo servers:

import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import typeDefs from './graphql/schema';
import resolvers from './graphql/resolvers';

const app = express();

async function startApolloServer() {
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.applyMiddleware({ app, path: '/graphql' });
}

startApolloServer();

export default app;

18. Modify Server

In src/server.ts, start the server and connect to the database:

import app from './app';
import sequelize from './config/database';

const PORT = process.env.PORT || 5000;

sequelize
.authenticate()
.then(() => {
console.log('Database connected');
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}/graphql`);
});
})
.catch((error) => {
console.error('Unable to connect to the database:', error);
});

19. Test the GraphQL API

With the server running, you can access the GraphQL Playground at http://localhost:5000/graphql.

Example Queries:

To fetch all products:

query {
products {
id
sku
name
price
}
}

To fetch a specific product by ID:

query {
product(id: 1) {
id
sku
name
price
}
}

Done! Now, you can create modern NodeJS microservices, avoiding legacy and slow Magento PHP use.

You can use the same approach with modern PHP Laravel’s Eloquent Orm — LaraGento project :

and Pythom Alchemy Orm project with magento!

More About NodeJS and Express :

--

--

Yegor Shytikov
Yegor Shytikov

Written by Yegor Shytikov

True Stories about Magento 2. Melting down metal server infrastructure into cloud solutions.

No responses yet