Odoo is an all-in-one open-source ERP platform, but its APIs are traditionally built around XML-RPC and JSON-RPC. For modern frontend frameworks like React, a more RESTful approach is often preferred. Thankfully, Odoo’s controller system allows us to define custom REST endpoints that can be consumed by any frontend.
In this guide, you’ll learn how to:
* Create a simple REST API in Odoo
* Fetch data from that API in a React app
* Solve common issues like CORS
Part 1: Create a REST API in Odoo
Let’s say you want to expose a list of products (names and prices). First, create a custom module (or use an existing one), and add an API controller.
File: my_module/controllers/api.py
from odoo import http
from odoo.http import request, Response
import json
class ApiController(http.Controller):
@http.route('/api/products', auth='public', type='http', methods=['GET'], csrf=False, cors="*")
def get_products(self):
"""
Returns a list of all products with their name and price.
"""
products = request.env['product.product'].sudo().search_read(
[], ['name', 'list_price']
)
return Response(
json.dumps(products),
content_type='application/json',
status=200
)
Explanation
* auth='public': This makes the API accessible without login (you can change it to 'user' for secured APIs).
* type='http': Enables standard HTTP responses (needed for Response()).
* methods=['GET']: Only allows GET requests.
* csrf=False: Disables CSRF protection for ease of frontend integration.
* cors="*": Enables Cross-Origin Resource Sharing for all domains (important for frontend apps).
* Response(): Used to manually format the HTTP response with proper headers and JSON content.
Folder Structure
Your custom module should be organized like this:
my_module/
+-- __init__.py
+-- __manifest__.py
+-- controllers/
+-- __init__.py
+-- api.py
__init__.py Files
# my_module/__init__.py
from . import controllers
# my_module/controllers/__init__.py
from . import api
Module Manifest (__manifest__.py)
Ensure dependencies include 'base' and 'product':
'depends': ['base', 'product'],
Restart Odoo and Install the Module
Once done, restart the Odoo server and install (or update) your custom module.
Test the endpoint:
curl http://localhost:8069/api/products
You should get a list of products in JSON format.
Part 2: Fetching Odoo Data in a React App
Create a React Project (Optional)
npx create-react-app odoo-react-client
cd odoo-react-client
npm start
Fetch Data from Odoo
Create a component to call the Odoo API:
// src/components/ProductList.js
import React, { useEffect, useState } from 'react';
const ProductList = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch('http://localhost:8069/api/products')
.then((res) => res.json())
.then((data) => setProducts(data))
.catch((err) => console.error('Failed to fetch products:', err));
}, []);
return (
<div>
<h2>Odoo Products</h2>
<ul>
{products.map((prod) => (
<li key={prod.id}>
{prod.name} - ${prod.list_price}
</li>
))}
</ul>
</div>
);
};
export default ProductList;
Use It in App.js
// src/App.js
import React from 'react';
import ProductList from './components/ProductList';
function App() {
return (
<div className="App">
<h1>React + Odoo Integration</h1>
<ProductList />
</div>
);
}
export default App;
Fixing CORS in Production
In development, cors="*" on the route is enough. But in production, consider restricting CORS to known frontend domains or using a reverse proxy (like NGINX) to manage headers securely.
For example:
@http.route('/api/products', auth='public', type='http', methods=['GET'], csrf=False, cors="https://yourdomain.com")
Summary
You’ve now successfully:
* Created a custom REST API in Odoo
* Exposed product data at /api/products
* Fetched it in a React frontend
* Handled CORS issues
This lightweight approach is great for building headless Odoo apps or external frontends powered by React, Vue, or any other JavaScript framework.
To read more about How to Configure Odoo REST API Module in Odoo 18, refer to our blog How to Configure Odoo REST API Module in Odoo 18.