PL/SQL25 min readBy Priyanshu Pandey

PL/SQL Masterclass: Building REST APIs in PL/SQL (ORDS)

Turn your Oracle Database into a modern web server. Learn how to use Oracle REST Data Services (ORDS) to expose PL/SQL procedures as secure, JSON-based RESTful APIs.

Integration Guide · PL/SQL Masterclass

REST APIs in PL/SQL: Unleashing Oracle with ORDS

You don't need a heavy Node.js or Java Spring Boot middle-tier to build APIs. Learn how Oracle REST Data Services (ORDS) seamlessly bridges the gap between HTTP JSON requests and native PL/SQL logic.

25 min read📅August 7, 2026✍️Priyanshu Pandey📚PL/SQL Masterclass

What is ORDS?

Oracle REST Data Services (ORDS) is a mid-tier Java application that connects to your Oracle Database. It maps HTTP URLs and verbs (GET, POST, PUT, DELETE) directly to database transactions.

Instead of writing a Node.js server that opens JDBC connections, executes queries, parses results into JSON, and returns them, you simply write PL/SQL. ORDS handles all the JSON serialization and HTTP protocol overhead for you automatically.

Auto-REST

Auto-REST Enabling Tables

The absolute fastest way to build an API is Auto-REST. If you have an EMPLOYEES table, you can generate full CRUD (Create, Read, Update, Delete) APIs against it with a single PL/SQL call.

PL/SQL
BEGIN
  ORDS.ENABLE_OBJECT(
    p_enabled      => TRUE,
    p_schema       => 'HR',
    p_object       => 'EMPLOYEES',
    p_object_type  => 'TABLE',
    p_object_alias => 'emps',
    p_auto_rest_auth => FALSE
  );
END;
/

Immediately, the following endpoints are live:

  • GET /ords/hr/emps/ (Returns all rows in JSON, with built-in pagination!)
  • GET /ords/hr/emps/101 (Returns employee 101)
  • POST /ords/hr/emps/ (Inserts a new employee from a JSON body)

Building Custom PL/SQL Endpoints

Auto-REST is great, but usually, you want to expose complex business logic, not just raw tables. For this, we build custom endpoints.

Step 1: Define the Module and Template

PL/SQL
BEGIN
  -- Create the base path: /api/inventory/
  ORDS.DEFINE_MODULE(
    p_module_name => 'inventory_api',
    p_base_path   => '/api/inventory/'
  );

  -- Define the specific endpoint template: /api/inventory/check/:item
  ORDS.DEFINE_TEMPLATE(
    p_module_name => 'inventory_api',
    p_pattern     => 'check/:item'
  );
END;
/

Step 2: Define the Handler (The PL/SQL Logic)

We attach a GET handler to our template. ORDS automatically converts any SYS_REFCURSOR into a perfectly formatted JSON array.

PL/SQL
BEGIN
  ORDS.DEFINE_HANDLER(
    p_module_name => 'inventory_api',
    p_pattern     => 'check/:item',
    p_method      => 'GET',
    p_source_type => ORDS.source_type_collection_feed,
    p_source      => 'SELECT loc, stock_on_hand FROM inv_status WHERE item = :item'
  );
END;
/

If a user hits GET /api/inventory/check/12345, ORDS passes 12345 into the :item bind variable, executes the SQL, and returns:

{"items": [{"loc": 100, "stock_on_hand": 50}, {"loc": 200, "stock_on_hand": 10}]}

Handling URI Parameters

In the example above, :item in the URI automatically bound to :item in the PL/SQL.

For POST requests, if the client sends a JSON body like {"status": "ACTIVE"}, you can access it in your PL/SQL handler by simply referencing the bind variable :status! ORDS parses the incoming JSON body automatically.

Security

Securing APIs with OAuth 2.0

Never leave your endpoints completely open. ORDS includes a built-in OAuth 2.0 authorization server.

  1. Create a Privilege: Group your modules under a privilege.
  2. Create a Client App: Generate a Client ID and Client Secret for your third-party consumer.
  3. Grant Access: Assign the privilege to the Client App.

The consumer must first POST their ID and Secret to the /oauth/token endpoint to receive a short-lived Bearer Token. They must pass this token in the Authorization header of subsequent API calls.

Common Gotchas

Important Gotchas

  • !

    If your PL/SQL handler throws an unhandled exception (like NO_DATA_FOUND), ORDS will generically return an HTTP 500 Internal Server Error. If you want to return a specific HTTP 404 Not Found, you must explicitly set the status code using :status_code := 404; in your exception block.

  • !

    If you need to access specific HTTP headers (like a custom X-Forwarded-For), you must map them explicitly using ORDS.DEFINE_PARAMETER before they become available as bind variables in your PL/SQL block.

Key Takeaways

Key Takeaways

  • ORDS eliminates the need for middle-tier applications when exposing database logic as APIs.
  • Use Auto-REST for instant CRUD endpoints on raw tables and views.
  • Use Modules, Templates, and Handlers to execute complex PL/SQL business logic behind REST URIs.
  • Secure your endpoints using the built-in OAuth 2.0 token workflows.
RetailCoder
All systems operational
v1.0 Live

RC:OMS

Multi-channel order management with double-entry inventory ledger. Amazon, Flipkart, Shopify, WooCommerce — one source of truth.

Launch demo →
v1.0 Live

RC:Storefront

Self-hosted headless e-commerce. Your server, your data, zero transaction fees. Native RC:OMS inventory sync.

Visit Storefront →
Pipeline

RC:Pulse

AI-powered retail analytics and demand forecasting — built natively on top of your RC:OMS and Storefront data.

Request early access →
Built in India 🇮🇳  ·  Architected by Priyanshu PandeyTalk to an engineer →