📚 Complete API Documentation Created
Files Generated:
1. API_ENDPOINTS.md (1,171 lines)
- Complete documentation of all 771 DocTypes in ERPNext
- Organized by 37 modules
- Sample record names for each DocType
- Full REST endpoint patterns
- Examples and usage instructions
2. generate_api_docs.py
- Python script to auto-discover and document all API endpoints
- Fetches live data from your ERPNext instance
- Can be re-run anytime to update documentation
3. discover_api_endpoints.sh
- Bash alternative for API discovery
- Lightweight script for quick checks
4. test_api.sh
- Ready-to-use API testing script
- Demonstrates authentication and common API calls
Key Features of the Documentation:
Complete Coverage:
- ✅ All 771 DocTypes documented
- ✅ 37 modules categorized
- ✅ Sample data for each DocType
- ✅ Single vs Standard vs Submittable types identified
- ✅ Child tables marked
API Endpoint Patterns for Each DocType:
# Standard DocTypes (e.g., Item, Customer)
GET /api/resource/{DocType} # List all
GET /api/resource/{DocType}/{name} # Get single
POST /api/resource/{DocType} # Create new
PUT /api/resource/{DocType}/{name} # Update
DELETE /api/resource/{DocType}/{name} # Delete
# Single DocTypes (e.g., System Settings)
GET /api/resource/{DocType}/{DocType} # Get singleton
Sample DocTypes by Category:
Standard DocTypes (most common):
- Customer, Item, Sales Order, Purchase Order, etc.
Single DocTypes (singletons):
- System Settings, Accounts Settings, Stock Settings, etc.
Submittable DocTypes (workflow):
- Sales Invoice, Purchase Invoice, Journal Entry, etc.
Child Tables (part of parent):
- Sales Order Item, Purchase Order Item, etc.
This commit is contained in:
parent
44a463d99c
commit
afe596e5ef
1171
API_ENDPOINTS.md
Normal file
1171
API_ENDPOINTS.md
Normal file
File diff suppressed because it is too large
Load Diff
297
API_GUIDE.md
Normal file
297
API_GUIDE.md
Normal file
@ -0,0 +1,297 @@
|
||||
# ERPNext API Access Guide
|
||||
|
||||
## Overview
|
||||
ERPNext provides comprehensive REST APIs for all its modules. The APIs follow RESTful conventions and return JSON responses.
|
||||
|
||||
**Important**: There is no browsable API index page at `/api/`. You must access specific endpoints directly.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Base URL
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
### Common API Endpoints
|
||||
|
||||
#### 1. **Authentication**
|
||||
```bash
|
||||
# Login
|
||||
POST http://localhost:8080/api/method/login
|
||||
{
|
||||
"usr": "Administrator",
|
||||
"pwd": "LocalDev123!"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. **Resource APIs**
|
||||
All DocTypes (database tables) in ERPNext are accessible via REST:
|
||||
|
||||
```bash
|
||||
# Get list of items
|
||||
GET http://localhost:8080/api/resource/Item
|
||||
|
||||
# Get specific item
|
||||
GET http://localhost:8080/api/resource/Item/{item_name}
|
||||
|
||||
# Create new item
|
||||
POST http://localhost:8080/api/resource/Item
|
||||
|
||||
# Update item
|
||||
PUT http://localhost:8080/api/resource/Item/{item_name}
|
||||
|
||||
# Delete item
|
||||
DELETE http://localhost:8080/api/resource/Item/{item_name}
|
||||
```
|
||||
|
||||
#### 3. **Method APIs**
|
||||
Custom server methods can be called:
|
||||
```bash
|
||||
POST http://localhost:8080/api/method/{method_path}
|
||||
```
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
### 1. **Session-based Authentication**
|
||||
After login, a session cookie is set which is used for subsequent requests.
|
||||
|
||||
### 2. **Token-based Authentication**
|
||||
Generate API keys from the user settings:
|
||||
|
||||
1. Login to ERPNext UI
|
||||
2. Go to Settings → My Settings
|
||||
3. Scroll to "API Access" section
|
||||
4. Generate API Secret
|
||||
5. Use in requests:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: token api_key:api_secret" \
|
||||
http://localhost:8080/api/resource/Item
|
||||
```
|
||||
|
||||
### 3. **Basic Authentication**
|
||||
```bash
|
||||
curl -u Administrator:LocalDev123! \
|
||||
http://localhost:8080/api/resource/Item
|
||||
```
|
||||
|
||||
## Live API Documentation
|
||||
|
||||
### 1. **Exploring Available DocTypes**
|
||||
Get a list of all available DocTypes (tables/resources):
|
||||
```bash
|
||||
# After login
|
||||
curl -b cookies.txt http://localhost:8080/api/resource/DocType
|
||||
```
|
||||
|
||||
### 2. **Swagger/OpenAPI Documentation**
|
||||
While ERPNext doesn't have built-in Swagger, you can explore APIs through:
|
||||
|
||||
- **Frappe Web UI**: After logging in, press `Ctrl+G` (or `Cmd+G` on Mac) to open the awesome bar and type any DocType name
|
||||
- **Developer Console**: Access via browser DevTools to see API calls made by the UI
|
||||
|
||||
### 3. **Interactive Console**
|
||||
Access the Python console to explore APIs:
|
||||
|
||||
```bash
|
||||
# Enter the backend container
|
||||
docker exec -it erpnext /bin/bash
|
||||
|
||||
# Start bench console
|
||||
bench --site frontend console
|
||||
|
||||
# Example commands in console:
|
||||
>>> frappe.get_all('Item')
|
||||
>>> frappe.get_doc('Item', 'ITEM-001')
|
||||
```
|
||||
|
||||
## Common API Operations
|
||||
|
||||
### Customer Management
|
||||
```bash
|
||||
# List customers
|
||||
GET /api/resource/Customer
|
||||
|
||||
# Create customer
|
||||
POST /api/resource/Customer
|
||||
{
|
||||
"customer_name": "Test Customer",
|
||||
"customer_type": "Company",
|
||||
"customer_group": "All Customer Groups",
|
||||
"territory": "All Territories"
|
||||
}
|
||||
```
|
||||
|
||||
### Item Management
|
||||
```bash
|
||||
# List items
|
||||
GET /api/resource/Item
|
||||
|
||||
# Create item
|
||||
POST /api/resource/Item
|
||||
{
|
||||
"item_code": "TEST-001",
|
||||
"item_name": "Test Item",
|
||||
"item_group": "All Item Groups",
|
||||
"stock_uom": "Nos"
|
||||
}
|
||||
```
|
||||
|
||||
### Sales Order
|
||||
```bash
|
||||
# Create sales order
|
||||
POST /api/resource/Sales%20Order
|
||||
{
|
||||
"customer": "Test Customer",
|
||||
"delivery_date": "2024-12-31",
|
||||
"items": [
|
||||
{
|
||||
"item_code": "TEST-001",
|
||||
"qty": 10,
|
||||
"rate": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## API Response Format
|
||||
|
||||
### Success Response
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
// Response data
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Response
|
||||
```json
|
||||
{
|
||||
"exc_type": "ValidationError",
|
||||
"exception": "Error details",
|
||||
"_server_messages": "..."
|
||||
}
|
||||
```
|
||||
|
||||
## Testing APIs
|
||||
|
||||
### Using cURL
|
||||
```bash
|
||||
# Login and save cookies
|
||||
curl -c cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"usr":"Administrator","pwd":"LocalDev123!"}' \
|
||||
http://localhost:8080/api/method/login
|
||||
|
||||
# Use cookies for subsequent requests
|
||||
curl -b cookies.txt \
|
||||
http://localhost:8080/api/resource/Item
|
||||
```
|
||||
|
||||
### Using Postman
|
||||
1. Import ERPNext collection (create your own based on endpoints above)
|
||||
2. Set base URL to `http://localhost:8080`
|
||||
3. Configure authentication in collection settings
|
||||
|
||||
### Using Python
|
||||
```python
|
||||
import requests
|
||||
|
||||
# Login
|
||||
session = requests.Session()
|
||||
login_response = session.post(
|
||||
'http://localhost:8080/api/method/login',
|
||||
json={'usr': 'Administrator', 'pwd': 'LocalDev123!'}
|
||||
)
|
||||
|
||||
# Get items
|
||||
items = session.get('http://localhost:8080/api/resource/Item')
|
||||
print(items.json())
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### 1. **Filters**
|
||||
```bash
|
||||
# Filter with conditions
|
||||
GET /api/resource/Item?filters=[["item_group","=","Products"]]
|
||||
|
||||
# Multiple filters
|
||||
GET /api/resource/Item?filters=[["item_group","=","Products"],["disabled","=",0]]
|
||||
```
|
||||
|
||||
### 2. **Field Selection**
|
||||
```bash
|
||||
# Select specific fields
|
||||
GET /api/resource/Item?fields=["item_code","item_name","standard_rate"]
|
||||
```
|
||||
|
||||
### 3. **Pagination**
|
||||
```bash
|
||||
# Limit and offset
|
||||
GET /api/resource/Item?limit_start=0&limit_page_length=20
|
||||
```
|
||||
|
||||
### 4. **Sorting**
|
||||
```bash
|
||||
# Order by field
|
||||
GET /api/resource/Item?order_by=modified%20desc
|
||||
```
|
||||
|
||||
## WebSocket API
|
||||
|
||||
ERPNext also provides WebSocket connections for real-time updates:
|
||||
|
||||
```javascript
|
||||
// Connect to WebSocket
|
||||
const socket = io('http://localhost:8080', {
|
||||
withCredentials: true
|
||||
});
|
||||
|
||||
// Listen for events
|
||||
socket.on('connect', () => {
|
||||
console.log('Connected to ERPNext WebSocket');
|
||||
});
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
ERPNext implements rate limiting for API calls:
|
||||
- Default: 60 requests per minute per IP
|
||||
- Can be configured in site_config.json
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Always use HTTPS in production**
|
||||
2. **Generate and use API tokens instead of passwords**
|
||||
3. **Implement IP whitelisting for API access**
|
||||
4. **Regular token rotation**
|
||||
5. **Monitor API usage logs**
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Debug Mode
|
||||
```bash
|
||||
# In the backend container
|
||||
bench --site frontend set-config developer_mode 1
|
||||
bench --site frontend clear-cache
|
||||
```
|
||||
|
||||
### View API Logs
|
||||
```bash
|
||||
# Check frappe logs
|
||||
docker exec -it erpnext tail -f sites/frontend/logs/frappe.log
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Frappe REST API Documentation](https://frappeframework.com/docs/user/en/api/rest)
|
||||
- [ERPNext API Reference](https://docs.erpnext.com/docs/user/manual/en/api)
|
||||
- [Frappe Client Scripts](https://frappeframework.com/docs/user/en/desk/scripting/client-script)
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Check the logs: `docker compose logs -f backend`
|
||||
- Access the console: `docker exec -it erpnext bench --site frontend console`
|
||||
- Visit the [ERPNext Forum](https://discuss.erpnext.com/) for community support
|
||||
25
CLAUDE.md
25
CLAUDE.md
@ -114,6 +114,31 @@ When changing `APP_VERSION` in `.env`:
|
||||
- **Network**: All services communicate through the `erpnext-local` Docker network
|
||||
- **Default Credentials**: Administrator / LocalDev123!
|
||||
|
||||
## API Development
|
||||
|
||||
### Accessing APIs
|
||||
ERPNext provides REST APIs accessible at `http://localhost:8080/api/`
|
||||
|
||||
### Common API Endpoints
|
||||
- **Login**: `POST /api/method/login`
|
||||
- **Resources**: `/api/resource/{DocType}`
|
||||
- **Methods**: `/api/method/{method_path}`
|
||||
|
||||
### Testing APIs
|
||||
```bash
|
||||
# Login and get session
|
||||
curl -c cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"usr":"Administrator","pwd":"LocalDev123!"}' \
|
||||
http://localhost:8080/api/method/login
|
||||
|
||||
# Use session for API calls
|
||||
curl -b cookies.txt http://localhost:8080/api/resource/Item
|
||||
```
|
||||
|
||||
### API Documentation
|
||||
See [API_GUIDE.md](API_GUIDE.md) for comprehensive API documentation.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Conflicts
|
||||
|
||||
11
README.md
11
README.md
@ -165,10 +165,21 @@ This deployment uses a microservices architecture with the following containers:
|
||||
- **configurator**: Initial configuration (runs once)
|
||||
- **create-site**: Site creation (runs once)
|
||||
|
||||
## API Access
|
||||
|
||||
ERPNext provides comprehensive REST APIs for integration. See [API_GUIDE.md](API_GUIDE.md) for detailed documentation on:
|
||||
- Authentication methods
|
||||
- REST API endpoints
|
||||
- WebSocket connections
|
||||
- API testing examples
|
||||
|
||||
Quick access: `http://localhost:8080/api/`
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ERPNext Documentation](https://docs.erpnext.com/)
|
||||
- [Frappe Framework Documentation](https://frappeframework.com/docs)
|
||||
- [Frappe REST API Documentation](https://frappeframework.com/docs/user/en/api/rest)
|
||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||
|
||||
## Contributing
|
||||
|
||||
190
discover_api_endpoints.sh
Executable file
190
discover_api_endpoints.sh
Executable file
@ -0,0 +1,190 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ERPNext API Discovery Script
|
||||
# This script discovers all available DocTypes and their endpoints
|
||||
|
||||
API_URL="http://localhost:8080"
|
||||
USERNAME="Administrator"
|
||||
PASSWORD="LocalDev123!"
|
||||
OUTPUT_FILE="API_ENDPOINTS.md"
|
||||
|
||||
echo "======================================"
|
||||
echo "ERPNext API Discovery Script"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# Login
|
||||
echo "Logging in..."
|
||||
curl -s -c cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"usr\":\"$USERNAME\",\"pwd\":\"$PASSWORD\"}" \
|
||||
$API_URL/api/method/login > /dev/null
|
||||
|
||||
# Get all DocTypes
|
||||
echo "Fetching all DocTypes..."
|
||||
ALL_DOCTYPES=$(curl -s -b cookies.txt "$API_URL/api/resource/DocType?limit_page_length=1000&fields=\[\"name\",\"module\",\"is_submittable\",\"issingle\"\]" | jq -r '.data')
|
||||
|
||||
# Start creating the documentation
|
||||
cat > $OUTPUT_FILE << 'EOF'
|
||||
# ERPNext API Endpoints Documentation
|
||||
|
||||
Generated on: $(date)
|
||||
|
||||
This document provides a comprehensive list of all available API endpoints in ERPNext.
|
||||
|
||||
## Authentication
|
||||
|
||||
All API calls require authentication. First, login to get a session:
|
||||
|
||||
```bash
|
||||
curl -c cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"usr":"Administrator","pwd":"your_password"}' \
|
||||
http://localhost:8080/api/method/login
|
||||
```
|
||||
|
||||
## API Endpoint Pattern
|
||||
|
||||
All DocTypes follow the same RESTful pattern:
|
||||
|
||||
- **List/Search**: `GET /api/resource/{DocType}`
|
||||
- **Get Single**: `GET /api/resource/{DocType}/{name}`
|
||||
- **Create**: `POST /api/resource/{DocType}`
|
||||
- **Update**: `PUT /api/resource/{DocType}/{name}`
|
||||
- **Delete**: `DELETE /api/resource/{DocType}/{name}`
|
||||
|
||||
## Available DocTypes and Endpoints
|
||||
|
||||
EOF
|
||||
|
||||
echo "" >> $OUTPUT_FILE
|
||||
echo "Processing DocTypes and getting sample data..."
|
||||
|
||||
# Process each module
|
||||
MODULES=$(echo "$ALL_DOCTYPES" | jq -r '.[].module' | sort -u)
|
||||
|
||||
for MODULE in $MODULES; do
|
||||
echo "Processing module: $MODULE"
|
||||
echo "" >> $OUTPUT_FILE
|
||||
echo "### Module: $MODULE" >> $OUTPUT_FILE
|
||||
echo "" >> $OUTPUT_FILE
|
||||
echo "| DocType | Single/List | Sample Names | Endpoints |" >> $OUTPUT_FILE
|
||||
echo "|---------|-------------|--------------|-----------|" >> $OUTPUT_FILE
|
||||
|
||||
# Get DocTypes for this module
|
||||
MODULE_DOCTYPES=$(echo "$ALL_DOCTYPES" | jq -r ".[] | select(.module==\"$MODULE\") | .name")
|
||||
|
||||
for DOCTYPE in $MODULE_DOCTYPES; do
|
||||
# URL encode the DocType name
|
||||
DOCTYPE_ENCODED=$(echo "$DOCTYPE" | sed 's/ /%20/g')
|
||||
|
||||
# Check if it's a single DocType
|
||||
IS_SINGLE=$(echo "$ALL_DOCTYPES" | jq -r ".[] | select(.name==\"$DOCTYPE\") | .issingle")
|
||||
|
||||
# Get sample records (limit to 3)
|
||||
SAMPLE_RECORDS=$(curl -s -b cookies.txt "$API_URL/api/resource/$DOCTYPE_ENCODED?limit_page_length=3&fields=\[\"name\"\]" 2>/dev/null | jq -r '.data[]?.name' 2>/dev/null | tr '\n' ', ' | sed 's/,$//' | sed 's/,/, /g')
|
||||
|
||||
if [ "$IS_SINGLE" == "1" ]; then
|
||||
TYPE="Single"
|
||||
ENDPOINTS="\`GET /api/resource/$DOCTYPE/$DOCTYPE\`"
|
||||
SAMPLE_RECORDS="$DOCTYPE"
|
||||
else
|
||||
TYPE="List"
|
||||
ENDPOINTS="\`/api/resource/$DOCTYPE\`"
|
||||
if [ -z "$SAMPLE_RECORDS" ]; then
|
||||
SAMPLE_RECORDS="No records"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Escape pipe characters in sample records
|
||||
SAMPLE_RECORDS=$(echo "$SAMPLE_RECORDS" | sed 's/|/\\|/g')
|
||||
|
||||
# Truncate if too long
|
||||
if [ ${#SAMPLE_RECORDS} -gt 50 ]; then
|
||||
SAMPLE_RECORDS="${SAMPLE_RECORDS:0:47}..."
|
||||
fi
|
||||
|
||||
echo "| $DOCTYPE | $TYPE | $SAMPLE_RECORDS | $ENDPOINTS |" >> $OUTPUT_FILE
|
||||
done
|
||||
done
|
||||
|
||||
# Add common query parameters section
|
||||
cat >> $OUTPUT_FILE << 'EOF'
|
||||
|
||||
## Common Query Parameters
|
||||
|
||||
### For List Endpoints
|
||||
|
||||
| Parameter | Description | Example |
|
||||
|-----------|-------------|---------|
|
||||
| `fields` | Select specific fields | `fields=["name","status"]` |
|
||||
| `filters` | Filter results | `filters=[["status","=","Active"]]` |
|
||||
| `limit_start` | Pagination offset | `limit_start=0` |
|
||||
| `limit_page_length` | Page size | `limit_page_length=20` |
|
||||
| `order_by` | Sort results | `order_by=modified desc` |
|
||||
|
||||
### Examples
|
||||
|
||||
#### Get list with filters
|
||||
```bash
|
||||
curl -b cookies.txt \
|
||||
"http://localhost:8080/api/resource/Item?filters=[[\"item_group\",\"=\",\"Products\"]]&fields=[\"item_code\",\"item_name\"]"
|
||||
```
|
||||
|
||||
#### Get single document
|
||||
```bash
|
||||
curl -b cookies.txt \
|
||||
"http://localhost:8080/api/resource/User/Administrator"
|
||||
```
|
||||
|
||||
#### Create new document
|
||||
```bash
|
||||
curl -b cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"doctype":"Item","item_code":"TEST-001","item_name":"Test Item","item_group":"Products","stock_uom":"Nos"}' \
|
||||
"http://localhost:8080/api/resource/Item"
|
||||
```
|
||||
|
||||
#### Update document
|
||||
```bash
|
||||
curl -b cookies.txt -X PUT \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"item_name":"Updated Test Item"}' \
|
||||
"http://localhost:8080/api/resource/Item/TEST-001"
|
||||
```
|
||||
|
||||
#### Delete document
|
||||
```bash
|
||||
curl -b cookies.txt -X DELETE \
|
||||
"http://localhost:8080/api/resource/Item/TEST-001"
|
||||
```
|
||||
|
||||
## Special Endpoints
|
||||
|
||||
### Authentication
|
||||
- `POST /api/method/login` - Login
|
||||
- `POST /api/method/logout` - Logout
|
||||
|
||||
### File Upload
|
||||
- `POST /api/method/upload_file` - Upload files
|
||||
|
||||
### Reports
|
||||
- `GET /api/method/frappe.desk.query_report.run` - Run reports
|
||||
|
||||
## Notes
|
||||
|
||||
1. **Single DocTypes**: These DocTypes have only one record (like System Settings) and use their name directly in the URL
|
||||
2. **URL Encoding**: DocType names with spaces must be URL encoded (e.g., "Sales Order" becomes "Sales%20Order")
|
||||
3. **Permissions**: Access to DocTypes depends on user permissions
|
||||
4. **Rate Limiting**: Default rate limit is 60 requests per minute
|
||||
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "======================================"
|
||||
echo "Discovery complete!"
|
||||
echo "Documentation saved to: $OUTPUT_FILE"
|
||||
echo "======================================"
|
||||
|
||||
# Clean up
|
||||
rm -f cookies.txt
|
||||
319
generate_api_docs.py
Executable file
319
generate_api_docs.py
Executable file
@ -0,0 +1,319 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
import urllib.parse
|
||||
|
||||
# Configuration
|
||||
API_URL = "http://localhost:8080"
|
||||
USERNAME = "Administrator"
|
||||
PASSWORD = "LocalDev123!"
|
||||
|
||||
def login():
|
||||
"""Login and return session"""
|
||||
session = requests.Session()
|
||||
response = session.post(
|
||||
f"{API_URL}/api/method/login",
|
||||
json={"usr": USERNAME, "pwd": PASSWORD}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
print("✓ Logged in successfully")
|
||||
return session
|
||||
else:
|
||||
print("✗ Login failed")
|
||||
return None
|
||||
|
||||
def get_all_doctypes(session):
|
||||
"""Fetch all DocTypes"""
|
||||
response = session.get(
|
||||
f"{API_URL}/api/resource/DocType",
|
||||
params={
|
||||
"limit_page_length": 1000,
|
||||
"fields": json.dumps(["name", "module", "issingle", "is_submittable", "istable"])
|
||||
}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.json().get("data", [])
|
||||
return []
|
||||
|
||||
def get_sample_records(session, doctype, limit=3):
|
||||
"""Get sample record names for a DocType"""
|
||||
try:
|
||||
# URL encode the DocType name
|
||||
doctype_encoded = urllib.parse.quote(doctype)
|
||||
response = session.get(
|
||||
f"{API_URL}/api/resource/{doctype_encoded}",
|
||||
params={
|
||||
"limit_page_length": limit,
|
||||
"fields": json.dumps(["name"])
|
||||
}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json().get("data", [])
|
||||
return [record.get("name", "") for record in data]
|
||||
except:
|
||||
pass
|
||||
return []
|
||||
|
||||
def generate_documentation(session):
|
||||
"""Generate comprehensive API documentation"""
|
||||
|
||||
print("Fetching all DocTypes...")
|
||||
doctypes = get_all_doctypes(session)
|
||||
print(f"Found {len(doctypes)} DocTypes")
|
||||
|
||||
# Group by module
|
||||
modules = {}
|
||||
for doctype in doctypes:
|
||||
module = doctype.get("module", "Unknown")
|
||||
if module not in modules:
|
||||
modules[module] = []
|
||||
modules[module].append(doctype)
|
||||
|
||||
# Sort modules
|
||||
sorted_modules = sorted(modules.keys())
|
||||
|
||||
# Generate markdown
|
||||
doc = []
|
||||
doc.append("# ERPNext API Endpoints Documentation")
|
||||
doc.append("")
|
||||
doc.append(f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
doc.append("")
|
||||
doc.append("This document provides a comprehensive list of all available API endpoints in ERPNext.")
|
||||
doc.append("")
|
||||
|
||||
# Authentication section
|
||||
doc.append("## Authentication")
|
||||
doc.append("")
|
||||
doc.append("All API calls require authentication. First, login to get a session:")
|
||||
doc.append("")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -c cookies.txt -X POST \\")
|
||||
doc.append(" -H \"Content-Type: application/json\" \\")
|
||||
doc.append(" -d '{\"usr\":\"Administrator\",\"pwd\":\"your_password\"}' \\")
|
||||
doc.append(" http://localhost:8080/api/method/login")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
|
||||
# API Pattern section
|
||||
doc.append("## API Endpoint Pattern")
|
||||
doc.append("")
|
||||
doc.append("All DocTypes follow the same RESTful pattern:")
|
||||
doc.append("")
|
||||
doc.append("- **List/Search**: `GET /api/resource/{DocType}`")
|
||||
doc.append("- **Get Single**: `GET /api/resource/{DocType}/{name}`")
|
||||
doc.append("- **Create**: `POST /api/resource/{DocType}`")
|
||||
doc.append("- **Update**: `PUT /api/resource/{DocType}/{name}`")
|
||||
doc.append("- **Delete**: `DELETE /api/resource/{DocType}/{name}`")
|
||||
doc.append("")
|
||||
|
||||
# Table of Contents
|
||||
doc.append("## Table of Contents")
|
||||
doc.append("")
|
||||
for module in sorted_modules:
|
||||
doc.append(f"- [{module}](#{module.lower().replace(' ', '-')})")
|
||||
doc.append("")
|
||||
|
||||
# DocTypes by Module
|
||||
doc.append("## Available DocTypes by Module")
|
||||
doc.append("")
|
||||
|
||||
total_processed = 0
|
||||
for module in sorted_modules:
|
||||
print(f"\nProcessing module: {module}")
|
||||
doc.append(f"### {module}")
|
||||
doc.append("")
|
||||
doc.append("| DocType | Type | Sample Names | API Endpoints |")
|
||||
doc.append("|---------|------|--------------|---------------|")
|
||||
|
||||
module_doctypes = sorted(modules[module], key=lambda x: x.get("name", ""))
|
||||
|
||||
for doctype_info in module_doctypes:
|
||||
doctype = doctype_info.get("name", "")
|
||||
issingle = doctype_info.get("issingle", 0)
|
||||
istable = doctype_info.get("istable", 0)
|
||||
is_submittable = doctype_info.get("is_submittable", 0)
|
||||
|
||||
# Determine type
|
||||
if issingle:
|
||||
dtype = "Single"
|
||||
elif istable:
|
||||
dtype = "Child Table"
|
||||
elif is_submittable:
|
||||
dtype = "Submittable"
|
||||
else:
|
||||
dtype = "Standard"
|
||||
|
||||
# Get sample records
|
||||
if issingle:
|
||||
samples = [doctype]
|
||||
elif istable:
|
||||
samples = ["(Child of parent doc)"]
|
||||
else:
|
||||
samples = get_sample_records(session, doctype)
|
||||
if not samples:
|
||||
samples = ["(No records)"]
|
||||
|
||||
# Format samples
|
||||
sample_str = ", ".join(str(s) for s in samples[:2])
|
||||
if len(sample_str) > 40:
|
||||
sample_str = sample_str[:37] + "..."
|
||||
|
||||
# Format endpoints
|
||||
doctype_url = urllib.parse.quote(doctype)
|
||||
if issingle:
|
||||
endpoints = f"`GET /api/resource/{doctype_url}/{doctype_url}`"
|
||||
else:
|
||||
endpoints = f"`/api/resource/{doctype_url}`"
|
||||
|
||||
doc.append(f"| {doctype} | {dtype} | {sample_str} | {endpoints} |")
|
||||
|
||||
total_processed += 1
|
||||
if total_processed % 10 == 0:
|
||||
print(f" Processed {total_processed} DocTypes...")
|
||||
|
||||
doc.append("")
|
||||
|
||||
print(f"\nProcessed {total_processed} DocTypes total")
|
||||
|
||||
# Common Query Parameters
|
||||
doc.append("## Common Query Parameters")
|
||||
doc.append("")
|
||||
doc.append("### For List Endpoints")
|
||||
doc.append("")
|
||||
doc.append("| Parameter | Description | Example |")
|
||||
doc.append("|-----------|-------------|---------|")
|
||||
doc.append("| `fields` | Select specific fields | `fields=[\"name\",\"status\"]` |")
|
||||
doc.append("| `filters` | Filter results | `filters=[[\"status\",\"=\",\"Active\"]]` |")
|
||||
doc.append("| `limit_start` | Pagination offset | `limit_start=0` |")
|
||||
doc.append("| `limit_page_length` | Page size | `limit_page_length=20` |")
|
||||
doc.append("| `order_by` | Sort results | `order_by=modified desc` |")
|
||||
doc.append("")
|
||||
|
||||
# Examples section
|
||||
doc.append("## Examples")
|
||||
doc.append("")
|
||||
doc.append("### Get list with filters")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -b cookies.txt \\")
|
||||
doc.append(" \"http://localhost:8080/api/resource/Item?filters=[[\\\"item_group\\\",\\\"=\\\",\\\"Products\\\"]]&fields=[\\\"item_code\\\",\\\"item_name\\\"]\"")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
doc.append("### Get single document")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -b cookies.txt \\")
|
||||
doc.append(" \"http://localhost:8080/api/resource/User/Administrator\"")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
doc.append("### Create new document")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -b cookies.txt -X POST \\")
|
||||
doc.append(" -H \"Content-Type: application/json\" \\")
|
||||
doc.append(" -d '{\"doctype\":\"Item\",\"item_code\":\"TEST-001\",\"item_name\":\"Test Item\",\"item_group\":\"Products\",\"stock_uom\":\"Nos\"}' \\")
|
||||
doc.append(" \"http://localhost:8080/api/resource/Item\"")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
doc.append("### Update document")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -b cookies.txt -X PUT \\")
|
||||
doc.append(" -H \"Content-Type: application/json\" \\")
|
||||
doc.append(" -d '{\"item_name\":\"Updated Test Item\"}' \\")
|
||||
doc.append(" \"http://localhost:8080/api/resource/Item/TEST-001\"")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
doc.append("### Delete document")
|
||||
doc.append("```bash")
|
||||
doc.append("curl -b cookies.txt -X DELETE \\")
|
||||
doc.append(" \"http://localhost:8080/api/resource/Item/TEST-001\"")
|
||||
doc.append("```")
|
||||
doc.append("")
|
||||
|
||||
# Special Endpoints
|
||||
doc.append("## Special Endpoints")
|
||||
doc.append("")
|
||||
doc.append("### Authentication")
|
||||
doc.append("- `POST /api/method/login` - Login")
|
||||
doc.append("- `POST /api/method/logout` - Logout")
|
||||
doc.append("")
|
||||
doc.append("### File Operations")
|
||||
doc.append("- `POST /api/method/upload_file` - Upload files")
|
||||
doc.append("- `GET /api/method/download_file` - Download files")
|
||||
doc.append("")
|
||||
doc.append("### Reports")
|
||||
doc.append("- `GET /api/method/frappe.desk.query_report.run` - Run reports")
|
||||
doc.append("")
|
||||
|
||||
# DocType Categories
|
||||
doc.append("## DocType Categories")
|
||||
doc.append("")
|
||||
doc.append("### Single DocTypes")
|
||||
doc.append("These DocTypes have only one record (singleton pattern):")
|
||||
doc.append("")
|
||||
single_docs = [d.get("name") for d in doctypes if d.get("issingle")]
|
||||
for doc_name in sorted(single_docs)[:20]: # Show first 20
|
||||
doc.append(f"- {doc_name}")
|
||||
if len(single_docs) > 20:
|
||||
doc.append(f"- ... and {len(single_docs) - 20} more")
|
||||
doc.append("")
|
||||
|
||||
doc.append("### Child Tables")
|
||||
doc.append("These DocTypes are child tables and cannot be accessed directly:")
|
||||
doc.append("")
|
||||
child_docs = [d.get("name") for d in doctypes if d.get("istable")]
|
||||
for doc_name in sorted(child_docs)[:20]: # Show first 20
|
||||
doc.append(f"- {doc_name}")
|
||||
if len(child_docs) > 20:
|
||||
doc.append(f"- ... and {len(child_docs) - 20} more")
|
||||
doc.append("")
|
||||
|
||||
doc.append("### Submittable DocTypes")
|
||||
doc.append("These DocTypes support document submission workflow:")
|
||||
doc.append("")
|
||||
submit_docs = [d.get("name") for d in doctypes if d.get("is_submittable")]
|
||||
for doc_name in sorted(submit_docs)[:20]: # Show first 20
|
||||
doc.append(f"- {doc_name}")
|
||||
if len(submit_docs) > 20:
|
||||
doc.append(f"- ... and {len(submit_docs) - 20} more")
|
||||
doc.append("")
|
||||
|
||||
# Notes
|
||||
doc.append("## Important Notes")
|
||||
doc.append("")
|
||||
doc.append("1. **URL Encoding**: DocType names with spaces must be URL encoded (e.g., \"Sales Order\" → \"Sales%20Order\")")
|
||||
doc.append("2. **Permissions**: Access to DocTypes depends on user permissions")
|
||||
doc.append("3. **Rate Limiting**: Default rate limit is 60 requests per minute")
|
||||
doc.append("4. **Single DocTypes**: Use the DocType name as both the resource and document name")
|
||||
doc.append("5. **Child Tables**: Cannot be accessed directly, only through their parent document")
|
||||
doc.append("6. **Submittable Documents**: Support additional states (Draft, Submitted, Cancelled)")
|
||||
doc.append("")
|
||||
|
||||
return "\n".join(doc)
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print("ERPNext API Documentation Generator")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
# Login
|
||||
session = login()
|
||||
if not session:
|
||||
print("Failed to login!")
|
||||
return
|
||||
|
||||
# Generate documentation
|
||||
documentation = generate_documentation(session)
|
||||
|
||||
# Save to file
|
||||
output_file = "API_ENDPOINTS.md"
|
||||
with open(output_file, "w") as f:
|
||||
f.write(documentation)
|
||||
|
||||
print()
|
||||
print("=" * 50)
|
||||
print(f"✓ Documentation saved to: {output_file}")
|
||||
print("=" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
44
test_api.sh
Executable file
44
test_api.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ERPNext API Test Script
|
||||
# This script demonstrates how to access ERPNext APIs
|
||||
|
||||
API_URL="http://localhost:8080"
|
||||
USERNAME="Administrator"
|
||||
PASSWORD="LocalDev123!"
|
||||
|
||||
echo "======================================"
|
||||
echo "ERPNext API Test Script"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 1. Login and save cookies
|
||||
echo "1. Logging in..."
|
||||
curl -s -c cookies.txt -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"usr\":\"$USERNAME\",\"pwd\":\"$PASSWORD\"}" \
|
||||
$API_URL/api/method/login | jq '.'
|
||||
|
||||
echo ""
|
||||
echo "2. Getting list of DocTypes (first 5)..."
|
||||
curl -s -b cookies.txt "$API_URL/api/resource/DocType?limit_page_length=5" | jq '.data[].name'
|
||||
|
||||
echo ""
|
||||
echo "3. Getting list of Users..."
|
||||
curl -s -b cookies.txt "$API_URL/api/resource/User?fields=\[\"name\",\"full_name\",\"enabled\"\]&limit_page_length=3" | jq '.'
|
||||
|
||||
echo ""
|
||||
echo "4. Getting system settings..."
|
||||
curl -s -b cookies.txt "$API_URL/api/resource/System%20Settings/System%20Settings" | jq '{country: .data.country, timezone: .data.time_zone}'
|
||||
|
||||
echo ""
|
||||
echo "5. Getting Company list..."
|
||||
curl -s -b cookies.txt "$API_URL/api/resource/Company" | jq '.'
|
||||
|
||||
echo ""
|
||||
echo "======================================"
|
||||
echo "API test complete!"
|
||||
echo "======================================"
|
||||
|
||||
# Clean up
|
||||
rm -f cookies.txt
|
||||
Loading…
Reference in New Issue
Block a user