Skip to content

feat: mle-ts-ords-backend template #301 #302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ The package offers the following templates, some of them connect to the database
- `node-react-todo`: A simple task manager template that uses Node.js and [React](https://react.dev/). It demonstrates the use of the database for Create, Read, Update and Delete (CRUD) operations. It is built by [vite](https://vitejs.dev/).
- `ords-remix-jwt-sample`: A full stack Concert Application made with [Remix](https://remix.run/) that showcases the [Oracle REST Data Services](https://www.oracle.com/database/technologies/appdev/rest.html) functionalities. Some extra configuration is required, learn more about it in the `ords-remix-jwt-sample` [Getting Started Guide](/templates/ords-remix-jwt-sample/README.md#getting-started).
- `mle-ts-sample`: A starter template application that demonstrates how backend applications can be developed using [Oracle Database Multilingual Engine (MLE)](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/introduction-to-mle.html). Requires SQLcl to be installed, for more information please read [README](/templates/mle-ts-sample/README.md)
- `mle-ts-ords-backend`: A starter template application that demonstrates how to expose MLE-based backend logic as RESTful endpoints using [Oracle REST Data Services](https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/) (ORDS). This template requires both SQLcl and ORDS to be installed. For more information, please refer to the [README](/templates/mle-ts-ords-backend/).

Each of the templates include documentation for you to get started with them, as well as NPM scripts for you to use right after generating the application.

Expand Down
11 changes: 10 additions & 1 deletion generators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ export default class extends Generator {
const { protocol, hostname, port, serviceName } = retrieveConnectionStringDetailsFromORAFile( path.join( walletPath, 'tnsnames.ora' ) );
this.options.connectionString = generateConnectionString( protocol, hostname, port, serviceName );
}
if(this.options.templateChoice.includes('mle-ts-ords-backend')) {
this.fs.copyTpl(
this.templatePath( '../../templates/mle-ts-sample' ),
this.destinationPath(),
{
appName: this.options.appName
}
);
}
// Copy files that are common to all of the templates.
this.fs.copyTpl(
this.templatePath( this.options.templateChoice ),
Expand Down Expand Up @@ -142,7 +151,7 @@ export default class extends Generator {
this.templatePath( `${this.options.templateChoice}/.env.example` ),
this.destinationPath( '.env.example' ),
);
} else if (this.options.templateChoice.includes('mle-ts-sample')) {
} else if (this.options.templateChoice.includes('mle-ts-sample') || this.options.templateChoice.includes('mle-ts-ords-backend')) {
if( 'walletPath' in this.options ) {
this.fs.copyTpl(
this.templatePath( `${this.options.templateChoice}/.env.example.wallet` ),
Expand Down
10 changes: 8 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export default class Generate extends Command {
'template': Flags.string({
char: 't',
description: 'Template to use',
options: ['node-vanilla', 'node-react', 'node-vue', 'node-react-todo', 'node-jet', 'node-angular', 'ords-remix-jwt-sample', 'mle-ts-sample'],
options: ['node-vanilla', 'node-react', 'node-vue', 'node-react-todo', 'node-jet', 'node-angular', 'ords-remix-jwt-sample', 'mle-ts-sample', 'mle-ts-ords-backend'],
multiple: false
}),

Expand Down Expand Up @@ -379,6 +379,11 @@ export default class Generate extends Command {
value: 'mle-ts-sample',
description: 'This creates an empty project with MLE and Oracle database connection starter code.'
},
{
name: 'mle-ts-ords-backend',
value: 'mle-ts-ords-backend',
description: 'Creates a starter project with MLE integration, Oracle Database connectivity, and scaffolded ORDS REST endpoints.'
},
],
pageSize: 10,
default: 'node-vanilla'
Expand Down Expand Up @@ -540,7 +545,8 @@ export default class Generate extends Command {
} );
}

if(templateChoice == 'mle-ts-sample'){
if(templateChoice == 'mle-ts-sample' || templateChoice == 'mle-ts-ords-backend')
{
// Ask the user for the path to SQLcl
Object.assign( configObject, {
sqlclPath: sqlclPath === '' ? await input(
Expand Down
16 changes: 16 additions & 0 deletions templates/mle-ts-ords-backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Database User
DB_USER=<%= connectionUsername %>
# Database User Password
DB_PASSWORD=<%= connectionPassword %>
# Connection string to your Autonomous Database/
# Oracle Database instance
CONNECT_STRING=<%= connectionString %>
# Oracle MLE Module name
MLE_MODULE=
# Optional HTTP Proxy Settings
# HTTPS_PROXY=
# HTTPS_PROXY_PORT=

# Path to your local SQL Developer Command Line
# installation
SQL_CL_PATH=<%= sqlclPath %>
19 changes: 19 additions & 0 deletions templates/mle-ts-ords-backend/.env.example.wallet
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Path to database wallet
WALLET_PATH=<%= walletPath %>

# Database User
DB_USER=<%= connectionUsername %>
# Database User Password
DB_PASSWORD=<%= connectionPassword %>
# Connection string to your Autonomous Database/
# Oracle Database instance
CONNECT_STRING=<%= connectionString %>
# Oracle MLE Module name
MLE_MODULE=
# Optional HTTP Proxy Settings
# HTTPS_PROXY=
# HTTPS_PROXY_PORT=

# Path to your local SQL Developer Command Line
# installation
SQL_CL_PATH=<%= sqlclPath %>
22 changes: 22 additions & 0 deletions templates/mle-ts-ords-backend/.gitignore.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.DS_Store

/.env
/.env.*
!/.env.example
!/.env.*.example
/server/utils/db/wallet
138 changes: 138 additions & 0 deletions templates/mle-ts-ords-backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<!-- markdownlint-disable MD013 -->

# In-Database JavaScript with ORDS Backend Template

An application template for Typescript and JavaScript developers showcasing REST API development using Oracle REST Data Services (ORDS) and Multilingual Engine (MLE).
**Extends [`mle-ts-sample`](../mle-ts-sample/README.md); see that template's readme for foundational features and explanations.**

## Description

This project builds upon the [mle-ts-sample](../mle-ts-sample/README.md) template by demonstrating how to create REST APIs within Oracle Database using [Oracle REST Data Services (ORDS)](https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/) and the [Multilingual Engine (MLE) JavaScript](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/introduction-to-mle.html).
In addition to the TODO functionality of `mle-ts-sample`, this template shows how to:

- Configure ORDS modules, templates, and handlers using SQL.
- Export JavaScript functions as REST endpoints via ORDS, with handler logic in an MLE module.
- Test REST endpoints with HTTP requests.
- Set up a development environment using Docker Compose, with Oracle Database and an ORDS server.

The basic application logic structure, build/deploy system, and database initialization approach remain as documented in the [mle-ts-sample README](../mle-ts-sample/README.md).

### Project Structure

Building on top of the standard [mle-ts-sample](../mle-ts-sample/README.md) layout, this template introduces several new files and conventions:

| Source File | Used For |
| ---------------------------------- | ------------------------------------------------------------------------------------- |
| `src/ords.ts` | Contains handler functions for ORDS REST endpoints. |
| `src/index.ts` | Exports the public API for the MLE module (see mle-ts-sample), plus ORDS handler implementations. |
| `utils/database/ords.sql` | SQL script to configure ORDS: installs ORDS modules, templates, and handlers bound to the MLE JS module. |
| `test/rest.test.js` | Automated tests for the REST API endpoints, using HTTP requests against the running ORDS backend. |
| `docker-compose.yml` | Docker Compose file spinning up both Oracle Database 23 Free (`db23`) and an ORDS node (`ords-node1`). |

All standard files and scripts from [`mle-ts-sample`](../mle-ts-sample/README.md) are also present and used as described in that README.

### Requirements

- [Oracle Database 23ai](https://www.oracle.com/database/) or Oracle Database Free (provided via Docker Compose).
- [Oracle REST Data Services](https://www.oracle.com/database/technologies/appdev/rest.html) (ORDS, configured for database access).
- [SQLcl](https://www.oracle.com/database/sqldeveloper/technologies/sqlcl) for deploying MLE modules.
- [Node.js](https://nodejs.org/).
- (Optional) [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) for quick local setup.
_Note: Any suitable container engine, such as [Podman](https://podman.io/), can be used in place of Docker._

### 1. Create the Application

Follow the general steps in the [mle-ts-sample/README](../mle-ts-sample/README.md#getting-started) to create your project, but **choose `mle-ts-ords-backend` as the template** during `@create-database-app` initialization.

### 2. (Optional) Start Development Environment with Docker Compose

To quickly launch both Oracle Database and ORDS locally:

```bash
docker-compose up
```
This starts:

- `db23` - Oracle Database 23 Free
- `ords-node1` - ORDS server configured to use `db23`

See the `docker-compose.yml` file (and its comments) for configuration options.

### 3. Install Project Dependencies

```bash
npm install
```

Installs all node modules, just like in mle-ts-sample.

### 4. Initialize the Database

Initialize the application data tables (as in mle-ts-sample):

```bash
npm run initdb
```

### 5. Build and Deploy the MLE Module

Build your application:

```bash
npm run build
```

Deploy the transpiled JS module to the database:

```bash
npm run deploy
```

Please check [mle-ts-sample/README](../mle-ts-sample/README.md) for more information about naming of the deployed modules.

## REST Endpoint Development

The main logic for REST endpoints is in [`src/ords.ts`](src/ords.ts).
This file exports handler functions used by ORDS to process REST requests. These handlers are linked to ORDS modules and templates via SQL in [`utils/database/ords.sql`](utils/database/ords.sql).

> **Before running any REST API tests, you must execute [`utils/database/ords.sql`](utils/database/ords.sql) to configure the ORDS modules, templates, and handlers.**
>
> **Important:** The MLE module name used in `ords.sql` is currently hardcoded. If you deployed your module under a different name, **edit `ords.sql` and replace the module name accordingly** to ensure ORDS invokes the correct module.

- `src/index.ts` exports public functions and handlers for deployment as an MLE module.
- ORDS is configured (via `ords.sql`) to call the correct JS handler for each endpoint.

## Application Testing

### Testing REST API Endpoints

After deploying the MLE module and executing the ORDS configuration (`utils/database/ords.sql`), you can test the exposed REST API endpoints.

#### Automated Testing

Run the REST API test suite (see [`test/rest.test.js`](test/rest.test.js)):

```bash
npm run test
```

This will send HTTP requests to the running ORDS server and verify the responses against expectations.

You can also use `curl`, `Postman`, or any HTTP client to manually test the REST endpoints.
Example (replace `[host]`, `[port]`, `<schema>`, and path as appropriate):

```bash
curl -X GET "http://localhost:8080/ords/<schema>/<ords_module_name>/<user_id>"
```

All endpoint routes, HTTP methods, and request/response formats are defined in the ORDS configuration and documented in `utils/database/ords.sql`.

## Other Testing, Cleanup, and Usage

You can use all application testing and database management approaches described in [mle-ts-sample/README](../mle-ts-sample/README.md) , including PLSQL call specifications, Oracle APEX, and other methods.

## Links for Further Reading
- [mle-ts-sample/README](../mle-ts-sample/README.md) - foundational documentation for this template.
- [ORDS Documentation](https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/index.html)
- [Docker Compose](https://docs.docker.com/compose/)
- [Podman Compose](https://docs.podman.io/en/v5.3.1/markdown/podman-compose.1.html)
32 changes: 32 additions & 0 deletions templates/mle-ts-ords-backend/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: '2.4'
services:
db23:
hostname: database
image: container-registry.oracle.com/database/free:latest
environment:
- ORACLE_PDB=FREEPDB1
- ORACLE_PWD=oracle
- DBHOST=database
ports:
- 1235:1521
mem_limit: 4096m
cpus: 2
ords-node1:
hostname: ords-node
image: container-registry.oracle.com/database/ords:latest
environment:
- CONN_STRING=//database:1521/FREEPDB1
- ORACLE_PWD=oracle
volumes:
- ./ords/config:/etc/ords/config
- ./apex:/opt/oracle/apex
ports:
- 8080:8080
healthcheck:
test: curl --noproxy "localhost" -f -k http://localhost:8080/ords/ || exit 1
interval: 30s
timeout: 10s
retries: 150
depends_on:
db23:
condition: service_healthy
3 changes: 3 additions & 0 deletions templates/mle-ts-ords-backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { createUserHandler, getUserHandler, deleteUserHandler, updateUserHandler } from './ords';
//needed for basic tests of MLE module calls
export { newUser, getUser, updateUser, deleteUser } from './todos';
40 changes: 40 additions & 0 deletions templates/mle-ts-ords-backend/src/ords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { newUser, getUser, deleteUser, updateUser } from './todos';

export async function createUserHandler(req, resp) {
const id = await newUser(req.query_parameters.name);
resp.status(201);
resp.content_type('application/json');
resp.json({ id });
}
export async function getUserHandler(req, resp) {
const userName = await getUser(parseInt(req.uri_parameters.id));
if(!userName) {
resp.status(404);
resp.content_type('application/json');
resp.json({msg: "User not found"});
} else {
resp.status(200);
resp.content_type('application/json');
resp.json(userName);
}
}
export async function deleteUserHandler(req, resp) {
const deleted = await deleteUser(parseInt(req.uri_parameters.id));
if (deleted > 0) {
resp.status(200);
} else {
resp.status(404);
}
resp.content_type('application/json');
resp.json({ rowsDeleted: deleted });
}
export async function updateUserHandler(req, resp) {
const updated = await updateUser(parseInt(req.uri_parameters.id),req.query_parameters.name);
if (updated > 0) {
resp.status(200);
} else {
resp.status(404);
}
resp.content_type('application/json');
resp.json({ rowsUpdated: updated });
}
Loading