mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 18:46:46 +00:00
Merge remote-tracking branch 'Simon/develop' into develop
This commit is contained in:
commit
5a418e556c
254
ai_summary/WEBUI_PROPS_ALPHABETICAL_LIST.md
Normal file
254
ai_summary/WEBUI_PROPS_ALPHABETICAL_LIST.md
Normal file
@ -0,0 +1,254 @@
|
||||
# WebUI Props - Alphabetical List
|
||||
|
||||
Complete list of all `webui_*` properties used in OBP-API, sorted alphabetically.
|
||||
|
||||
These properties can be:
|
||||
- Set in props files (e.g., `default.props`)
|
||||
- Stored in the database via WebUiProps table
|
||||
- Retrieved via API: `GET /obp/v6.0.0/webui-props/{PROP_NAME}`
|
||||
|
||||
---
|
||||
|
||||
## Complete List (56 properties)
|
||||
|
||||
1. `webui_agree_terms_url`
|
||||
2. `webui_api_documentation_bottom_url`
|
||||
3. `webui_api_documentation_url`
|
||||
4. `webui_api_explorer_url`
|
||||
5. `webui_api_manager_url`
|
||||
6. `webui_customer_user_invitation_email_from`
|
||||
7. `webui_customer_user_invitation_email_html_text`
|
||||
8. `webui_customer_user_invitation_email_subject`
|
||||
9. `webui_customer_user_invitation_email_text`
|
||||
10. `webui_developer_user_invitation_email_from`
|
||||
11. `webui_developer_user_invitation_email_html_text`
|
||||
12. `webui_developer_user_invitation_email_subject`
|
||||
13. `webui_developer_user_invitation_email_text`
|
||||
14. `webui_direct_login_documentation_url`
|
||||
15. `webui_dummy_user_logins`
|
||||
16. `webui_faq_data_text`
|
||||
17. `webui_faq_email`
|
||||
18. `webui_faq_url`
|
||||
19. `webui_favicon_link_url`
|
||||
20. `webui_featured_sdks_external_link`
|
||||
21. `webui_footer2_logo_left_url`
|
||||
22. `webui_footer2_middle_text`
|
||||
23. `webui_get_started_text`
|
||||
24. `webui_header_logo_left_url`
|
||||
25. `webui_header_logo_right_url`
|
||||
26. `webui_index_page_about_section_background_image_url`
|
||||
27. `webui_index_page_about_section_text`
|
||||
28. `webui_legal_notice_html_text`
|
||||
29. `webui_login_button_text`
|
||||
30. `webui_login_page_instruction_title`
|
||||
31. `webui_login_page_special_instructions`
|
||||
32. `webui_main_faq_external_link`
|
||||
33. `webui_main_partners`
|
||||
34. `webui_main_style_sheet`
|
||||
35. `webui_oauth_1_documentation_url`
|
||||
36. `webui_oauth_2_documentation_url`
|
||||
37. `webui_obp_cli_url`
|
||||
38. `webui_override_style_sheet`
|
||||
39. `webui_page_title_prefix`
|
||||
40. `webui_post_consumer_registration_more_info_text`
|
||||
41. `webui_post_consumer_registration_more_info_url`
|
||||
42. `webui_post_consumer_registration_submit_button_value`
|
||||
43. `webui_post_user_invitation_submit_button_value`
|
||||
44. `webui_post_user_invitation_terms_and_conditions_checkbox_value`
|
||||
45. `webui_privacy_policy`
|
||||
46. `webui_privacy_policy_url`
|
||||
47. `webui_sandbox_introduction`
|
||||
48. `webui_sdks_url`
|
||||
49. `webui_show_dummy_user_tokens`
|
||||
50. `webui_signup_body_password_repeat_text`
|
||||
51. `webui_signup_form_submit_button_value`
|
||||
52. `webui_signup_form_title_text`
|
||||
53. `webui_social_handle`
|
||||
54. `webui_social_logo_url`
|
||||
55. `webui_social_title`
|
||||
56. `webui_social_url`
|
||||
57. `webui_subscriptions_button_text`
|
||||
58. `webui_subscriptions_invitation_text`
|
||||
59. `webui_subscriptions_url`
|
||||
60. `webui_support_email`
|
||||
61. `webui_support_platform_url`
|
||||
62. `webui_terms_and_conditions`
|
||||
63. `webui_top_text`
|
||||
64. `webui_user_invitation_notice_text`
|
||||
65. `webui_vendor_support_html_url`
|
||||
|
||||
---
|
||||
|
||||
## Properties by Category
|
||||
|
||||
### Branding & UI
|
||||
- `webui_favicon_link_url`
|
||||
- `webui_footer2_logo_left_url`
|
||||
- `webui_footer2_middle_text`
|
||||
- `webui_header_logo_left_url`
|
||||
- `webui_header_logo_right_url`
|
||||
- `webui_index_page_about_section_background_image_url`
|
||||
- `webui_index_page_about_section_text`
|
||||
- `webui_main_style_sheet`
|
||||
- `webui_override_style_sheet`
|
||||
- `webui_page_title_prefix`
|
||||
- `webui_top_text`
|
||||
|
||||
### Documentation & Links
|
||||
- `webui_agree_terms_url`
|
||||
- `webui_api_documentation_bottom_url`
|
||||
- `webui_api_documentation_url`
|
||||
- `webui_api_explorer_url`
|
||||
- `webui_api_manager_url`
|
||||
- `webui_direct_login_documentation_url`
|
||||
- `webui_faq_url`
|
||||
- `webui_featured_sdks_external_link`
|
||||
- `webui_main_faq_external_link`
|
||||
- `webui_oauth_1_documentation_url`
|
||||
- `webui_oauth_2_documentation_url`
|
||||
- `webui_obp_cli_url`
|
||||
- `webui_privacy_policy_url`
|
||||
- `webui_sdks_url`
|
||||
- `webui_support_platform_url`
|
||||
- `webui_vendor_support_html_url`
|
||||
|
||||
### Login & Signup
|
||||
- `webui_login_button_text`
|
||||
- `webui_login_page_instruction_title`
|
||||
- `webui_login_page_special_instructions`
|
||||
- `webui_signup_body_password_repeat_text`
|
||||
- `webui_signup_form_submit_button_value`
|
||||
- `webui_signup_form_title_text`
|
||||
|
||||
### Legal & Terms
|
||||
- `webui_legal_notice_html_text`
|
||||
- `webui_privacy_policy`
|
||||
- `webui_terms_and_conditions`
|
||||
|
||||
### User Invitations - Customer
|
||||
- `webui_customer_user_invitation_email_from`
|
||||
- `webui_customer_user_invitation_email_html_text`
|
||||
- `webui_customer_user_invitation_email_subject`
|
||||
- `webui_customer_user_invitation_email_text`
|
||||
|
||||
### User Invitations - Developer
|
||||
- `webui_developer_user_invitation_email_from`
|
||||
- `webui_developer_user_invitation_email_html_text`
|
||||
- `webui_developer_user_invitation_email_subject`
|
||||
- `webui_developer_user_invitation_email_text`
|
||||
|
||||
### User Invitations - General
|
||||
- `webui_post_user_invitation_submit_button_value`
|
||||
- `webui_post_user_invitation_terms_and_conditions_checkbox_value`
|
||||
- `webui_user_invitation_notice_text`
|
||||
|
||||
### Consumer Registration
|
||||
- `webui_post_consumer_registration_more_info_text`
|
||||
- `webui_post_consumer_registration_more_info_url`
|
||||
- `webui_post_consumer_registration_submit_button_value`
|
||||
|
||||
### Developer Tools
|
||||
- `webui_dummy_user_logins`
|
||||
- `webui_show_dummy_user_tokens`
|
||||
|
||||
### Support & Contact
|
||||
- `webui_faq_data_text`
|
||||
- `webui_faq_email`
|
||||
- `webui_support_email`
|
||||
|
||||
### Social Media
|
||||
- `webui_social_handle`
|
||||
- `webui_social_logo_url`
|
||||
- `webui_social_title`
|
||||
- `webui_social_url`
|
||||
|
||||
### Subscriptions
|
||||
- `webui_subscriptions_button_text`
|
||||
- `webui_subscriptions_invitation_text`
|
||||
- `webui_subscriptions_url`
|
||||
|
||||
### Other
|
||||
- `webui_get_started_text`
|
||||
- `webui_main_partners`
|
||||
- `webui_sandbox_introduction`
|
||||
|
||||
---
|
||||
|
||||
## Environment Variable Mapping
|
||||
|
||||
WebUI props can be set via environment variables with the `OBP_` prefix:
|
||||
|
||||
```bash
|
||||
# Props file format:
|
||||
webui_api_explorer_url=https://apiexplorer.example.com
|
||||
|
||||
# Environment variable format:
|
||||
OBP_WEBUI_API_EXPLORER_URL=https://apiexplorer.example.com
|
||||
```
|
||||
|
||||
**Conversion rule:**
|
||||
- Add `OBP_` prefix
|
||||
- Convert to UPPERCASE
|
||||
- Replace `.` with `_`
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Get Single WebUI Prop
|
||||
```
|
||||
GET /obp/v6.0.0/webui-props/{WEBUI_PROP_NAME}
|
||||
GET /obp/v6.0.0/webui-props/{WEBUI_PROP_NAME}?active=true
|
||||
```
|
||||
|
||||
### Get All WebUI Props
|
||||
```
|
||||
GET /obp/v6.0.0/management/webui_props
|
||||
GET /obp/v6.0.0/management/webui_props?what=active
|
||||
GET /obp/v6.0.0/management/webui_props?what=database
|
||||
GET /obp/v6.0.0/management/webui_props?what=config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### In Props File
|
||||
```properties
|
||||
webui_api_explorer_url=https://apiexplorer.openbankproject.com
|
||||
webui_header_logo_left_url=https://static.openbankproject.com/logo.png
|
||||
webui_override_style_sheet=https://static.openbankproject.com/css/custom.css
|
||||
```
|
||||
|
||||
### As Environment Variables
|
||||
```yaml
|
||||
env:
|
||||
- name: OBP_WEBUI_API_EXPLORER_URL
|
||||
value: 'https://apiexplorer.openbankproject.com'
|
||||
- name: OBP_WEBUI_HEADER_LOGO_LEFT_URL
|
||||
value: 'https://static.openbankproject.com/logo.png'
|
||||
- name: OBP_WEBUI_OVERRIDE_STYLE_SHEET
|
||||
value: 'https://static.openbankproject.com/css/custom.css'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- All webui props are **optional** - the system has default values
|
||||
- Database values take **precedence** over props file values
|
||||
- Use `?active=true` query parameter to get database value OR fallback to default
|
||||
- Props are case-sensitive (always use lowercase `webui_`)
|
||||
- User invitation email props were renamed in Sept 2021 (see release notes)
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- API Glossary: `webui_props` entry
|
||||
- User Invitation Guide: `USER_INVITATION_API_ENDPOINTS.md`
|
||||
- WebUI Props Endpoint: `WEBUI_PROP_SINGLE_GET_ENDPOINT.md`
|
||||
|
||||
---
|
||||
|
||||
**Total Count:** 65 webui properties
|
||||
277
ai_summary/WEBUI_PROPS_LOGGING_GUIDE.md
Normal file
277
ai_summary/WEBUI_PROPS_LOGGING_GUIDE.md
Normal file
@ -0,0 +1,277 @@
|
||||
# WebUI Props API - Logging Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The WebUI Props endpoints in v6.0.0 have **extensive logging** to help with debugging and monitoring. This guide shows you what to search for in your logs.
|
||||
|
||||
---
|
||||
|
||||
## Logged Endpoints
|
||||
|
||||
### 1. Get All WebUI Props
|
||||
**Endpoint:** `GET /obp/v6.0.0/management/webui_props`
|
||||
|
||||
### 2. Get Single WebUI Prop
|
||||
**Endpoint:** `GET /obp/v6.0.0/webui-props/{PROP_NAME}`
|
||||
|
||||
---
|
||||
|
||||
## Log Patterns for GET /management/webui_props
|
||||
|
||||
### Entry Log
|
||||
```
|
||||
========== GET /obp/v6.0.0/management/webui_props called with what={VALUE} ==========
|
||||
```
|
||||
|
||||
**Search for:**
|
||||
```bash
|
||||
grep "GET /obp/v6.0.0/management/webui_props called" logs/obp-api.log
|
||||
```
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
2025-01-15 10:23:45 INFO - ========== GET /obp/v6.0.0/management/webui_props called with what=active ==========
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Result Summary Log
|
||||
```
|
||||
========== GET /obp/v6.0.0/management/webui_props returning {COUNT} records ==========
|
||||
```
|
||||
|
||||
**Search for:**
|
||||
```bash
|
||||
grep "GET /obp/v6.0.0/management/webui_props returning" logs/obp-api.log
|
||||
```
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
2025-01-15 10:23:45 INFO - ========== GET /obp/v6.0.0/management/webui_props returning 65 records ==========
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Individual Property Logs
|
||||
```
|
||||
- name: {PROP_NAME}, value: {PROP_VALUE}, webUiPropsId: {ID}
|
||||
```
|
||||
|
||||
**Search for:**
|
||||
```bash
|
||||
grep "name: webui_" logs/obp-api.log
|
||||
```
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
2025-01-15 10:23:45 INFO - - name: webui_api_explorer_url, value: https://apiexplorer.example.com, webUiPropsId: Some(web-ui-props-id)
|
||||
2025-01-15 10:23:45 INFO - - name: webui_header_logo_left_url, value: https://static.example.com/logo.png, webUiPropsId: Some(default)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Exit Log
|
||||
```
|
||||
========== END GET /obp/v6.0.0/management/webui_props ==========
|
||||
```
|
||||
|
||||
**Search for:**
|
||||
```bash
|
||||
grep "END GET /obp/v6.0.0/management/webui_props" logs/obp-api.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Log Patterns for GET /webui-props/{PROP_NAME}
|
||||
|
||||
### No Explicit Entry/Exit Logs
|
||||
|
||||
The single property endpoint (`GET /webui-props/{PROP_NAME}`) does **NOT** have dedicated entry/exit logs like the management endpoint.
|
||||
|
||||
However, you can still track it through:
|
||||
|
||||
### Standard API Request Logs
|
||||
```bash
|
||||
grep "GET /obp/v6.0.0/webui-props/" logs/obp-api.log
|
||||
```
|
||||
|
||||
### Error Logs (if property not found)
|
||||
```
|
||||
OBP-08003: WebUi prop not found. Please specify a valid value for WEBUI_PROP_NAME.
|
||||
```
|
||||
|
||||
**Search for:**
|
||||
```bash
|
||||
grep "OBP-08003" logs/obp-api.log
|
||||
grep "WebUi prop not found" logs/obp-api.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Log Sequence Example
|
||||
|
||||
When calling `GET /obp/v6.0.0/management/webui_props?what=active`:
|
||||
|
||||
```
|
||||
2025-01-15 10:23:45.123 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - ========== GET /obp/v6.0.0/management/webui_props called with what=active ==========
|
||||
2025-01-15 10:23:45.234 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - ========== GET /obp/v6.0.0/management/webui_props returning 65 records ==========
|
||||
2025-01-15 10:23:45.235 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - name: webui_agree_terms_url, value: https://example.com/terms, webUiPropsId: Some(default)
|
||||
2025-01-15 10:23:45.236 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - name: webui_api_documentation_url, value: https://docs.example.com, webUiPropsId: Some(default)
|
||||
2025-01-15 10:23:45.237 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - name: webui_api_explorer_url, value: https://apiexplorer.example.com, webUiPropsId: Some(web-ui-123)
|
||||
...
|
||||
(63 more property logs)
|
||||
...
|
||||
2025-01-15 10:23:45.300 [http-nio-8080-exec-1] INFO code.api.v6_0_0.APIMethods600$ - ========== END GET /obp/v6.0.0/management/webui_props ==========
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful grep Commands
|
||||
|
||||
### 1. Find all webui_props calls
|
||||
```bash
|
||||
grep "GET /obp/v6.0.0/management/webui_props called" logs/obp-api.log
|
||||
```
|
||||
|
||||
### 2. Count how many props were returned
|
||||
```bash
|
||||
grep "returning.*records" logs/obp-api.log | grep webui_props
|
||||
```
|
||||
|
||||
### 3. See all property values for a specific call
|
||||
```bash
|
||||
# Get timestamp from entry log, then search around that time
|
||||
grep "2025-01-15 10:23:45" logs/obp-api.log | grep "name: webui_"
|
||||
```
|
||||
|
||||
### 4. Find specific property value
|
||||
```bash
|
||||
grep "name: webui_api_explorer_url" logs/obp-api.log
|
||||
```
|
||||
|
||||
### 5. Monitor live calls
|
||||
```bash
|
||||
tail -f logs/obp-api.log | grep "webui_props"
|
||||
```
|
||||
|
||||
### 6. Find errors related to webui props
|
||||
```bash
|
||||
grep -i "error" logs/obp-api.log | grep -i "webui"
|
||||
grep "OBP-08" logs/obp-api.log # WebUI props error codes
|
||||
```
|
||||
|
||||
### 7. Get all logs for a single request (if you know the timestamp)
|
||||
```bash
|
||||
grep "2025-01-15 10:23:45" logs/obp-api.log | grep -A 100 "webui_props called"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Log Levels
|
||||
|
||||
All webui_props logging uses **INFO** level:
|
||||
|
||||
```scala
|
||||
logger.info(s"========== GET /obp/v6.0.0/management/webui_props called with what=$what ==========")
|
||||
logger.info(s"========== GET /obp/v6.0.0/management/webui_props returning ${result.size} records ==========")
|
||||
logger.info(s" - name: ${prop.name}, value: ${prop.value}, webUiPropsId: ${prop.webUiPropsId}")
|
||||
logger.info(s"========== END GET /obp/v6.0.0/management/webui_props ==========")
|
||||
```
|
||||
|
||||
**Make sure your logging configuration includes INFO level for `code.api.v6_0_0.APIMethods600`**
|
||||
|
||||
---
|
||||
|
||||
## Code Reference
|
||||
|
||||
### Management Endpoint Logging
|
||||
**File:** `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
**Lines:** 3505, 3534-3540
|
||||
|
||||
```scala
|
||||
logger.info(s"========== GET /obp/v6.0.0/management/webui_props called with what=$what ==========")
|
||||
// ... processing ...
|
||||
logger.info(s"========== GET /obp/v6.0.0/management/webui_props returning ${result.size} records ==========")
|
||||
result.foreach { prop =>
|
||||
logger.info(s" - name: ${prop.name}, value: ${prop.value}, webUiPropsId: ${prop.webUiPropsId}")
|
||||
}
|
||||
logger.info(s"========== END GET /obp/v6.0.0/management/webui_props ==========")
|
||||
```
|
||||
|
||||
### Single Prop Endpoint
|
||||
**File:** `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
**Lines:** 3406-3438
|
||||
|
||||
**No explicit logging** - relies on standard API framework logging.
|
||||
|
||||
---
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
### If you don't see logs:
|
||||
|
||||
1. **Check log level configuration:**
|
||||
```properties
|
||||
# In logback.xml or similar
|
||||
<logger name="code.api.v6_0_0.APIMethods600" level="INFO"/>
|
||||
```
|
||||
|
||||
2. **Verify the endpoint is being called:**
|
||||
```bash
|
||||
# Look for any v6.0.0 API calls
|
||||
grep "v6.0.0" logs/obp-api.log
|
||||
```
|
||||
|
||||
3. **Check for authentication errors:**
|
||||
```bash
|
||||
grep "canGetWebUiProps" logs/obp-api.log
|
||||
```
|
||||
|
||||
4. **Look for the call in access logs:**
|
||||
```bash
|
||||
grep "management/webui_props" logs/access.log
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **No logs appear:**
|
||||
- User doesn't have `CanGetWebUiProps` entitlement
|
||||
- Wrong endpoint URL (check for typos: `webui_props` vs `webui-props`)
|
||||
- Log level set too high (WARN or ERROR instead of INFO)
|
||||
|
||||
2. **Logs show 0 records:**
|
||||
- No database props configured
|
||||
- No config file props found
|
||||
- Check `what` parameter value
|
||||
|
||||
3. **Property not found in logs:**
|
||||
- Typo in property name (case-sensitive)
|
||||
- Property not in database or config file
|
||||
- Using wrong `what` parameter
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**To track webui_props API calls, search for:**
|
||||
|
||||
```bash
|
||||
# Primary search patterns
|
||||
grep "GET /obp/v6.0.0/management/webui_props called" logs/obp-api.log
|
||||
grep "GET /obp/v6.0.0/management/webui_props returning" logs/obp-api.log
|
||||
grep "name: webui_" logs/obp-api.log
|
||||
grep "END GET /obp/v6.0.0/management/webui_props" logs/obp-api.log
|
||||
|
||||
# Single property endpoint (less logging)
|
||||
grep "GET /obp/v6.0.0/webui-props/" logs/obp-api.log
|
||||
|
||||
# Errors
|
||||
grep "OBP-08003" logs/obp-api.log
|
||||
```
|
||||
|
||||
**The management endpoint has comprehensive logging showing:**
|
||||
- When it was called
|
||||
- What parameter was used (`what=active/database/config`)
|
||||
- How many records returned
|
||||
- Every single property name, value, and ID
|
||||
- When processing completed
|
||||
221
ai_summary/WEBUI_PROPS_V600_IMPROVEMENTS.md
Normal file
221
ai_summary/WEBUI_PROPS_V600_IMPROVEMENTS.md
Normal file
@ -0,0 +1,221 @@
|
||||
# WebUI Props v6.0.0 Improvements
|
||||
|
||||
## Summary
|
||||
|
||||
Enhanced the v6.0.0 `/webui-props` endpoint with better filtering, source tracking, and proper precedence handling.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Fixed Endpoint Precedence in v6.0.0
|
||||
|
||||
**Problem:** v6.0.0 was using v5.1.0's `getWebUiProps` endpoint instead of its own because v5.1.0 routes were listed first.
|
||||
|
||||
**Solution:** Changed route ordering in `OBPAPI6_0_0.scala`:
|
||||
|
||||
```scala
|
||||
// Before:
|
||||
private val endpoints: List[OBPEndpoint] = endpointsOf5_1_0_without_root ++ endpointsOf6_0_0
|
||||
|
||||
// After:
|
||||
private val endpoints: List[OBPEndpoint] = endpointsOf6_0_0.toList ++ endpointsOf5_1_0_without_root
|
||||
```
|
||||
|
||||
**Result:** v6.0.0 endpoints now take precedence over earlier versions automatically.
|
||||
|
||||
### 2. Fixed `what=active` Logic
|
||||
|
||||
**Problem:** `what=active` was returning ALL props (database + config), creating duplicates when the same prop existed in both sources.
|
||||
|
||||
**Before:**
|
||||
```scala
|
||||
case "active" =>
|
||||
val implicitWebUiPropsRemovedDuplicated = if(explicitWebUiProps.nonEmpty){
|
||||
val duplicatedProps = explicitWebUiProps.map(explicitWebUiProp =>
|
||||
implicitWebUiProps.filter(_.name == explicitWebUiProp.name)).flatten
|
||||
implicitWebUiProps diff duplicatedProps
|
||||
} else {
|
||||
implicitWebUiProps.distinct
|
||||
}
|
||||
explicitWebUiProps ++ implicitWebUiPropsRemovedDuplicated
|
||||
```
|
||||
|
||||
**After:**
|
||||
```scala
|
||||
case "active" =>
|
||||
// Return one value per prop: database value if exists, otherwise config value
|
||||
val databasePropNames = explicitWebUiPropsWithSource.map(_.name).toSet
|
||||
val configPropsNotInDatabase = implicitWebUiProps.distinct.filterNot(prop =>
|
||||
databasePropNames.contains(prop.name))
|
||||
explicitWebUiPropsWithSource ++ configPropsNotInDatabase
|
||||
```
|
||||
|
||||
**Result:** Returns ONE value per property name - database value if it exists, otherwise config value.
|
||||
|
||||
### 3. Added `source` Field to Track Prop Origin
|
||||
|
||||
**Problem:** Frontend had no way to know if a prop was editable (database) or read-only (config).
|
||||
|
||||
**Solution:** Added `source` field to `WebUiPropsCommons`:
|
||||
|
||||
```scala
|
||||
case class WebUiPropsCommons(
|
||||
name: String,
|
||||
value: String,
|
||||
webUiPropsId: Option[String] = None,
|
||||
source: String = "database"
|
||||
) extends WebUiPropsT with JsonFieldReName
|
||||
```
|
||||
|
||||
Each prop now includes:
|
||||
- `source="database"` for props stored in the database (editable via API)
|
||||
- `source="config"` for props from configuration file (read-only)
|
||||
|
||||
### 4. Updated Documentation
|
||||
|
||||
Enhanced ResourceDoc descriptions to clarify:
|
||||
- `what=active`: Returns one value per prop (database overrides config)
|
||||
- `what=database`: Returns ONLY database props
|
||||
- `what=config`: Returns ONLY config props
|
||||
- Added `source` field explanation in response fields section
|
||||
|
||||
## Query Parameters
|
||||
|
||||
### GET /obp/v6.0.0/webui-props
|
||||
|
||||
**`what` parameter (optional, default: "active"):**
|
||||
|
||||
| Value | Behavior | Use Case |
|
||||
|-------|----------|----------|
|
||||
| `active` | One value per prop: database if exists, else config | Frontend display - get effective values |
|
||||
| `database` | ONLY database-stored props | Admin UI - see what's been customized |
|
||||
| `config` | ONLY config file defaults | Admin UI - see available defaults |
|
||||
|
||||
### GET /obp/v6.0.0/webui-props/{PROP_NAME}
|
||||
|
||||
**`active` parameter (optional boolean string, default: "false"):**
|
||||
|
||||
| Value | Behavior |
|
||||
|-------|----------|
|
||||
| `false` or omitted | Only database prop (fails if not in database) |
|
||||
| `true` | Database prop, or fallback to config default |
|
||||
|
||||
## Response Format
|
||||
|
||||
```json
|
||||
{
|
||||
"webui_props": [
|
||||
{
|
||||
"name": "webui_api_explorer_url",
|
||||
"value": "https://custom.example.com",
|
||||
"webui_props_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"source": "database"
|
||||
},
|
||||
{
|
||||
"name": "webui_hello_message",
|
||||
"value": "Welcome to OBP",
|
||||
"webui_props_id": "default",
|
||||
"source": "config"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Get active props (effective values)
|
||||
```bash
|
||||
GET /obp/v6.0.0/webui-props
|
||||
GET /obp/v6.0.0/webui-props?what=active
|
||||
```
|
||||
Returns all props with database values taking precedence over config defaults.
|
||||
|
||||
### Get only customized props
|
||||
```bash
|
||||
GET /obp/v6.0.0/webui-props?what=database
|
||||
```
|
||||
Shows which props have been explicitly set via API.
|
||||
|
||||
### Get only config defaults
|
||||
```bash
|
||||
GET /obp/v6.0.0/webui-props?what=config
|
||||
```
|
||||
Shows all available default values from `sample.props.template`.
|
||||
|
||||
### Get single prop with fallback
|
||||
```bash
|
||||
GET /obp/v6.0.0/webui-props/webui_api_explorer_url?active=true
|
||||
```
|
||||
Returns database value if exists, otherwise config default.
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
The `source` field enables UIs to:
|
||||
|
||||
1. **Show edit buttons only for editable props:**
|
||||
```javascript
|
||||
if (prop.source === "database" || canCreateWebUiProps) {
|
||||
showEditButton();
|
||||
}
|
||||
```
|
||||
|
||||
2. **Display visual indicators:**
|
||||
```javascript
|
||||
const icon = prop.source === "database" ? "custom" : "default";
|
||||
const tooltip = prop.source === "database"
|
||||
? "Custom value (editable)"
|
||||
: "Default from config (read-only)";
|
||||
```
|
||||
|
||||
3. **Prevent edit attempts on config props:**
|
||||
```javascript
|
||||
if (prop.source === "config") {
|
||||
showWarning("This is a config default. Create a database override to customize.");
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Notes
|
||||
|
||||
- **Backward Compatibility:** v5.1.0 and v3.1.0 endpoints unchanged
|
||||
- **Default Value:** `source` defaults to `"database"` for backward compatibility
|
||||
- **No Schema Changes:** Uses existing `WebUiPropsCommons` case class with new optional field
|
||||
|
||||
## Files Changed
|
||||
|
||||
1. `obp-api/src/main/scala/code/webuiprops/WebUiProps.scala`
|
||||
- Added `source` field to `WebUiPropsCommons`
|
||||
|
||||
2. `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
- Fixed `what=active` logic to return one value per prop
|
||||
- Added `source` field to all WebUiPropsCommons instantiations
|
||||
- Updated ResourceDoc for both endpoints
|
||||
|
||||
3. `obp-api/src/main/scala/code/api/v6_0_0/OBPAPI6_0_0.scala`
|
||||
- Changed endpoint order to prioritize v6.0.0 over v5.1.0
|
||||
|
||||
## Testing
|
||||
|
||||
Test the different query modes:
|
||||
|
||||
```bash
|
||||
# Get all active props (database + config, no duplicates)
|
||||
curl http://localhost:8080/obp/v6.0.0/webui-props?what=active
|
||||
|
||||
# Get only database props
|
||||
curl http://localhost:8080/obp/v6.0.0/webui-props?what=database
|
||||
|
||||
# Get only config props
|
||||
curl http://localhost:8080/obp/v6.0.0/webui-props?what=config
|
||||
|
||||
# Get single prop (database only)
|
||||
curl http://localhost:8080/obp/v6.0.0/webui-props/webui_api_explorer_url
|
||||
|
||||
# Get single prop with config fallback
|
||||
curl http://localhost:8080/obp/v6.0.0/webui-props/webui_api_explorer_url?active=true
|
||||
```
|
||||
|
||||
Verify that:
|
||||
1. No duplicate property names in `what=active` response
|
||||
2. Each prop includes `source` field
|
||||
3. Database props have `source="database"`
|
||||
4. Config props have `source="config"`
|
||||
5. v6.0.0 endpoint is actually being called (check logs)
|
||||
276
ai_summary/WEBUI_PROPS_VISIBILITY.md
Normal file
276
ai_summary/WEBUI_PROPS_VISIBILITY.md
Normal file
@ -0,0 +1,276 @@
|
||||
# WebUI Props Endpoint Visibility in API Explorer
|
||||
|
||||
## Question
|
||||
**Why don't I see `/obp/v6.0.0/management/webui_props` in API Explorer II?**
|
||||
|
||||
---
|
||||
|
||||
## Answer
|
||||
|
||||
The endpoint **IS implemented** in v6.0.0, but it **requires authentication and a specific role**, which is why it may not appear in API Explorer II.
|
||||
|
||||
---
|
||||
|
||||
## Endpoint Details
|
||||
|
||||
### `/obp/v6.0.0/management/webui_props`
|
||||
|
||||
**File:** `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
**Lines:** 3442-3498 (ResourceDoc), 3501-3542 (Implementation)
|
||||
|
||||
**Status:** ✅ **Implemented in v6.0.0**
|
||||
|
||||
**Authentication:** ✅ **Required** - Uses `authenticatedAccess(cc)`
|
||||
|
||||
**Authorization:** ✅ **Required** - Needs `CanGetWebUiProps` entitlement
|
||||
|
||||
**Tag:** `apiTagWebUiProps` (WebUi-Props)
|
||||
|
||||
**API Version:** `ApiVersion.v6_0_0`
|
||||
|
||||
---
|
||||
|
||||
## Why It's Not Visible in API Explorer II
|
||||
|
||||
### Reason 1: You're Not Logged In
|
||||
API Explorer II may hide endpoints that require authentication when you're not logged in.
|
||||
|
||||
**Solution:** Log in to API Explorer II with a user account.
|
||||
|
||||
### Reason 2: You Don't Have the Required Role
|
||||
The endpoint requires the `CanGetWebUiProps` entitlement.
|
||||
|
||||
**Code (line 3513):**
|
||||
```scala
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetWebUiProps, callContext)
|
||||
```
|
||||
|
||||
**Solution:** Grant yourself the `CanGetWebUiProps` role.
|
||||
|
||||
### Reason 3: API Explorer II Filters
|
||||
API Explorer II may filter endpoints based on:
|
||||
- Tags
|
||||
- Authentication requirements
|
||||
- Your current roles/entitlements
|
||||
- API version selection
|
||||
|
||||
**Solution:** Check API Explorer II filters and settings.
|
||||
|
||||
---
|
||||
|
||||
## How to Verify the Endpoint Exists
|
||||
|
||||
### 1. Check via Direct API Call
|
||||
|
||||
```bash
|
||||
# Get an authentication token first
|
||||
curl -X POST https://your-api.com/obp/v6.0.0/my/logins/direct \
|
||||
-H "DirectLogin: username=YOUR_USERNAME, password=YOUR_PASSWORD, consumer_key=YOUR_CONSUMER_KEY"
|
||||
|
||||
# Then call the endpoint
|
||||
curl -X GET https://your-api.com/obp/v6.0.0/management/webui_props \
|
||||
-H "Authorization: DirectLogin token=YOUR_TOKEN"
|
||||
```
|
||||
|
||||
### 2. Check the ResourceDoc Endpoint
|
||||
|
||||
```bash
|
||||
# Get all resource docs for v6.0.0
|
||||
curl https://your-api.com/obp/v6.0.0/resource-docs/obp
|
||||
|
||||
# Search for webui_props
|
||||
curl https://your-api.com/obp/v6.0.0/resource-docs/obp | grep -i "webui_props"
|
||||
```
|
||||
|
||||
### 3. Search Code
|
||||
|
||||
```bash
|
||||
cd OBP-API
|
||||
grep -r "management/webui_props" obp-api/src/main/scala/code/api/v6_0_0/
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
APIMethods600.scala: "/management/webui_props",
|
||||
APIMethods600.scala: case "management" :: "webui_props":: Nil JsonGet req => {
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Required Role
|
||||
|
||||
### Role Name
|
||||
`CanGetWebUiProps`
|
||||
|
||||
### How to Grant This Role
|
||||
|
||||
#### Via API (requires admin access)
|
||||
```bash
|
||||
POST /obp/v4.0.0/users/USER_ID/entitlements
|
||||
|
||||
{
|
||||
"bank_id": "",
|
||||
"role_name": "CanGetWebUiProps"
|
||||
}
|
||||
```
|
||||
|
||||
#### Via Database (for development)
|
||||
```sql
|
||||
-- Check if user has the role
|
||||
SELECT * FROM entitlement
|
||||
WHERE user_id = 'YOUR_USER_ID'
|
||||
AND role_name = 'CanGetWebUiProps';
|
||||
|
||||
-- Grant the role (if needed)
|
||||
INSERT INTO entitlement (entitlement_id, user_id, role_name, bank_id)
|
||||
VALUES (uuid(), 'YOUR_USER_ID', 'CanGetWebUiProps', '');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## All WebUI Props Endpoints in v6.0.0
|
||||
|
||||
### 1. Get All WebUI Props (Management)
|
||||
```
|
||||
GET /obp/v6.0.0/management/webui_props
|
||||
GET /obp/v6.0.0/management/webui_props?what=active
|
||||
GET /obp/v6.0.0/management/webui_props?what=database
|
||||
GET /obp/v6.0.0/management/webui_props?what=config
|
||||
```
|
||||
- **Authentication:** Required
|
||||
- **Role:** `CanGetWebUiProps`
|
||||
- **Tag:** `apiTagWebUiProps`
|
||||
|
||||
### 2. Get Single WebUI Prop (Public-ish)
|
||||
```
|
||||
GET /obp/v6.0.0/webui-props/WEBUI_PROP_NAME
|
||||
GET /obp/v6.0.0/webui-props/WEBUI_PROP_NAME?active=true
|
||||
```
|
||||
- **Authentication:** NOT required (anonymous access)
|
||||
- **Role:** None
|
||||
- **Tag:** `apiTagWebUiProps`
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
# No authentication needed!
|
||||
curl https://your-api.com/obp/v6.0.0/webui-props/webui_api_explorer_url?active=true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code References
|
||||
|
||||
### ResourceDoc Definition
|
||||
**File:** `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
**Lines:** 3442-3498
|
||||
|
||||
```scala
|
||||
staticResourceDocs += ResourceDoc(
|
||||
getWebUiProps,
|
||||
implementedInApiVersion, // ApiVersion.v6_0_0
|
||||
nameOf(getWebUiProps),
|
||||
"GET",
|
||||
"/management/webui_props",
|
||||
"Get WebUiProps",
|
||||
s"""...""",
|
||||
EmptyBody,
|
||||
ListResult("webui_props", ...),
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagWebUiProps),
|
||||
Some(List(canGetWebUiProps)) // ← ROLE REQUIRED
|
||||
)
|
||||
```
|
||||
|
||||
### Implementation
|
||||
**File:** `obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala`
|
||||
**Lines:** 3501-3542
|
||||
|
||||
```scala
|
||||
lazy val getWebUiProps: OBPEndpoint = {
|
||||
case "management" :: "webui_props":: Nil JsonGet req => {
|
||||
cc => implicit val ec = EndpointContext(Some(cc))
|
||||
val what = ObpS.param("what").getOrElse("active")
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc) // ← AUTH REQUIRED
|
||||
...
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId,
|
||||
ApiRole.canGetWebUiProps, callContext) // ← ROLE CHECK
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Role Definition
|
||||
**File:** `obp-api/src/main/scala/code/api/util/ApiRole.scala`
|
||||
**Lines:** ~1300+
|
||||
|
||||
```scala
|
||||
case class CanGetWebUiProps(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetWebUiProps = CanGetWebUiProps()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison with Other Versions
|
||||
|
||||
### v3.1.0
|
||||
- `GET /obp/v3.1.0/management/webui_props` - **Authentication + CanGetWebUiProps required**
|
||||
|
||||
### v5.1.0
|
||||
- `GET /obp/v5.1.0/management/webui_props` - **No authentication required** (different implementation)
|
||||
|
||||
### v6.0.0
|
||||
- `GET /obp/v6.0.0/management/webui_props` - **Authentication + CanGetWebUiProps required**
|
||||
- `GET /obp/v6.0.0/webui-props/{NAME}` - **No authentication required** (new endpoint)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Aspect | Status | Details |
|
||||
|--------|--------|---------|
|
||||
| **Implemented in v6.0.0** | ✅ Yes | Line 3442-3542 in APIMethods600.scala |
|
||||
| **Authentication Required** | ✅ Yes | Uses `authenticatedAccess(cc)` |
|
||||
| **Role Required** | ✅ Yes | `CanGetWebUiProps` |
|
||||
| **Tag** | `apiTagWebUiProps` | WebUi-Props category |
|
||||
| **Why Not Visible** | Security | Hidden from non-authenticated users or users without role |
|
||||
| **How to See It** | 1. Log in to API Explorer<br>2. Grant yourself `CanGetWebUiProps` role<br>3. Refresh API Explorer | |
|
||||
|
||||
---
|
||||
|
||||
## Alternative: Use the Public Endpoint
|
||||
|
||||
If you just want to **read** WebUI props without authentication, use the **single prop endpoint**:
|
||||
|
||||
```bash
|
||||
# Public access - no authentication needed
|
||||
curl https://your-api.com/obp/v6.0.0/webui-props/webui_api_explorer_url?active=true
|
||||
```
|
||||
|
||||
This endpoint is available in v6.0.0 and does **NOT** require authentication or roles.
|
||||
|
||||
---
|
||||
|
||||
## Testing Commands
|
||||
|
||||
```bash
|
||||
# 1. Check if you're logged in
|
||||
curl https://your-api.com/obp/v6.0.0/users/current \
|
||||
-H "Authorization: DirectLogin token=YOUR_TOKEN"
|
||||
|
||||
# 2. Check your roles
|
||||
curl https://your-api.com/obp/v6.0.0/users/current \
|
||||
-H "Authorization: DirectLogin token=YOUR_TOKEN" | grep -i "CanGetWebUiProps"
|
||||
|
||||
# 3. Try to call the endpoint
|
||||
curl https://your-api.com/obp/v6.0.0/management/webui_props \
|
||||
-H "Authorization: DirectLogin token=YOUR_TOKEN"
|
||||
|
||||
# If you get UserHasMissingRoles error, you need to grant yourself the role
|
||||
# If you get 200 OK, the endpoint works!
|
||||
```
|
||||
@ -24,6 +24,7 @@ import code.api.dynamic.entity.OBPAPIDynamicEntity
|
||||
import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
|
||||
import code.util.Helper
|
||||
import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN}
|
||||
import net.liftweb.http.S
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.enums.ContentParam
|
||||
import com.openbankproject.commons.model.enums.ContentParam.{ALL, DYNAMIC, STATIC}
|
||||
@ -735,39 +736,124 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
|
||||
|
|
||||
|API_VERSION is the version you want documentation about e.g. v6.0.0
|
||||
|
|
||||
|You may filter this endpoint using the 'tags' url parameter e.g. ?tags=Account,Bank
|
||||
|## Query Parameters
|
||||
|
|
||||
|(All endpoints are given one or more tags which for used in grouping)
|
||||
|You may filter this endpoint using the following optional query parameters:
|
||||
|
|
||||
|You may filter this endpoint using the 'functions' url parameter e.g. ?functions=getBanks,bankById
|
||||
|**tags** - Filter by endpoint tags (comma-separated list)
|
||||
| • Example: ?tags=Account,Bank or ?tags=Account-Firehose
|
||||
| • All endpoints are given one or more tags which are used for grouping
|
||||
| • Empty values will return error OBP-10053
|
||||
|
|
||||
|(Each endpoint is implemented in the OBP Scala code by a 'function')
|
||||
|**functions** - Filter by function names (comma-separated list)
|
||||
| • Example: ?functions=getBanks,bankById
|
||||
| • Each endpoint is implemented in the OBP Scala code by a 'function'
|
||||
| • Empty values will return error OBP-10054
|
||||
|
|
||||
|**content** - Filter by endpoint type
|
||||
| • Values: static, dynamic, all (case-insensitive)
|
||||
| • static: Only show static/core API endpoints
|
||||
| • dynamic: Only show dynamic/custom endpoints
|
||||
| • all: Show both static and dynamic endpoints (default)
|
||||
| • Invalid values will return error OBP-10052
|
||||
|
|
||||
|**locale** - Language for localized documentation
|
||||
| • Example: ?locale=en_GB or ?locale=es_ES
|
||||
| • Supported locales: en_GB, es_ES, ro_RO
|
||||
| • Invalid locales will return error OBP-10041
|
||||
|
|
||||
|**api-collection-id** - Filter by API collection UUID
|
||||
| • Example: ?api-collection-id=4e866c86-60c3-4268-a221-cb0bbf1ad221
|
||||
| • Returns only endpoints belonging to the specified collection
|
||||
| • Empty values will return error OBP-10055
|
||||
|
|
||||
|This endpoint generates OpenAPI 3.1 compliant documentation with modern JSON Schema support.
|
||||
|
|
||||
|See the Resource Doc endpoint for more information.
|
||||
|
|
||||
| Note: Resource Docs are cached, TTL is ${GET_DYNAMIC_RESOURCE_DOCS_TTL} seconds
|
||||
|Note: Resource Docs are cached, TTL is ${GET_DYNAMIC_RESOURCE_DOCS_TTL} seconds
|
||||
|
|
||||
|Following are more examples:
|
||||
|## Examples
|
||||
|
|
||||
|Basic usage:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi
|
||||
|
|
||||
|Filter by tags:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?tags=Account,Bank
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?tags=Account-Firehose
|
||||
|
|
||||
|Filter by content type:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?content=static
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?content=dynamic
|
||||
|
|
||||
|Filter by functions:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?functions=getBanks,bankById
|
||||
|
|
||||
|Combine multiple parameters:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?content=static&tags=Account-Firehose
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?tags=Account,Bank,PSD2&functions=getBanks,bankById
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?content=static&locale=en_GB&tags=Account
|
||||
|
|
||||
|Filter by API collection:
|
||||
|${getObpApiRoot}/v6.0.0/resource-docs/v6.0.0/openapi?api-collection-id=4e866c86-60c3-4268-a221-cb0bbf1ad221
|
||||
|
|
||||
""",
|
||||
EmptyBody,
|
||||
EmptyBody,
|
||||
InvalidApiVersionString ::
|
||||
ApiVersionNotSupported ::
|
||||
InvalidLocale ::
|
||||
InvalidContentParameter ::
|
||||
InvalidTagsParameter ::
|
||||
InvalidFunctionsParameter ::
|
||||
InvalidApiCollectionIdParameter ::
|
||||
UnknownError :: Nil,
|
||||
List(apiTagDocumentation, apiTagApi)
|
||||
)
|
||||
|
||||
/**
|
||||
* OpenAPI 3.1 endpoint with comprehensive parameter validation.
|
||||
*
|
||||
* This endpoint generates OpenAPI 3.1 documentation with the following validated query parameters:
|
||||
* - tags: Comma-separated list of tags to filter endpoints (e.g., ?tags=Account,Bank)
|
||||
* - functions: Comma-separated list of function names to filter endpoints
|
||||
* - content: Filter type - "static", "dynamic", or "all"
|
||||
* - locale: Language code for localization (e.g., "en_GB", "es_ES")
|
||||
* - api-collection-id: UUID to filter by specific API collection
|
||||
*
|
||||
* Parameter validation guards ensure:
|
||||
* - Empty parameters (e.g., ?tags=) return 400 error
|
||||
* - Invalid content values return 400 error with valid options
|
||||
* - All parameters are properly trimmed and sanitized
|
||||
*
|
||||
* Examples:
|
||||
* - ?content=static&tags=Account-Firehose
|
||||
* - ?tags=Account,Bank&functions=getBanks,bankById
|
||||
* - ?content=dynamic&locale=en_GB
|
||||
*/
|
||||
def getResourceDocsOpenAPI31 : OBPEndpoint = {
|
||||
case "resource-docs" :: requestedApiVersionString :: "openapi" :: Nil JsonGet _ => {
|
||||
cc => {
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
val (resourceDocTags, partialFunctions, locale, contentParam, apiCollectionIdParam) = ResourceDocsAPIMethodsUtil.getParams()
|
||||
|
||||
// Early validation for empty parameters using underlying S to bypass ObpS filtering
|
||||
if (S.param("tags").exists(_.trim.isEmpty)) {
|
||||
Full(errorJsonResponse(InvalidTagsParameter, 400))
|
||||
} else if (S.param("functions").exists(_.trim.isEmpty)) {
|
||||
Full(errorJsonResponse(InvalidFunctionsParameter, 400))
|
||||
} else if (S.param("api-collection-id").exists(_.trim.isEmpty)) {
|
||||
Full(errorJsonResponse(InvalidApiCollectionIdParameter, 400))
|
||||
} else {
|
||||
val (resourceDocTags, partialFunctions, locale, contentParam, apiCollectionIdParam) = ResourceDocsAPIMethodsUtil.getParams()
|
||||
for {
|
||||
// Validate content parameter if provided
|
||||
_ <- if (S.param("content").isDefined && contentParam.isEmpty) {
|
||||
Helper.booleanToFuture(failMsg = InvalidContentParameter, cc = cc.callContext) {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
Future.successful(true)
|
||||
}
|
||||
requestedApiVersion <- NewStyle.function.tryons(s"$InvalidApiVersionString Current Version is $requestedApiVersionString", 400, cc.callContext) {
|
||||
ApiVersionUtils.valueOf(requestedApiVersionString)
|
||||
}
|
||||
@ -819,8 +905,9 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
|
||||
convertResourceDocsToOpenAPI31JvalueAndSetCache(cacheKey, requestedApiVersionString, resourceDocsJsonFiltered)
|
||||
}
|
||||
}
|
||||
} yield {
|
||||
(openApiJValue, HttpCode.`200`(cc.callContext))
|
||||
} yield {
|
||||
(openApiJValue, HttpCode.`200`(cc.callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -980,7 +1067,7 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{
|
||||
case _ => Empty
|
||||
}
|
||||
|
||||
def stringToContentParam (x: String) : Option[ContentParam] = x.toLowerCase match {
|
||||
def stringToContentParam (x: String) : Option[ContentParam] = x.toLowerCase.trim match {
|
||||
case "dynamic" => Some(DYNAMIC)
|
||||
case "static" => Some(STATIC)
|
||||
case "all" => Some(ALL)
|
||||
@ -1000,14 +1087,18 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{
|
||||
case Empty => None
|
||||
case _ => {
|
||||
val commaSeparatedList : String = rawTagsParam.getOrElse("")
|
||||
val tagList : List[String] = commaSeparatedList.trim().split(",").toList
|
||||
val resourceDocTags =
|
||||
for {
|
||||
y <- tagList
|
||||
} yield {
|
||||
ResourceDocTag(y)
|
||||
}
|
||||
Some(resourceDocTags)
|
||||
val tagList : List[String] = commaSeparatedList.trim().split(",").toList.filter(_.nonEmpty)
|
||||
if (tagList.nonEmpty) {
|
||||
val resourceDocTags =
|
||||
for {
|
||||
y <- tagList
|
||||
} yield {
|
||||
ResourceDocTag(y.trim())
|
||||
}
|
||||
Some(resourceDocTags)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug(s"tagsOption is $tags")
|
||||
@ -1023,14 +1114,18 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{
|
||||
case Empty => None
|
||||
case _ => {
|
||||
val commaSeparatedList : String = rawPartialFunctionNames.getOrElse("")
|
||||
val stringList : List[String] = commaSeparatedList.trim().split(",").toList
|
||||
val pfns =
|
||||
for {
|
||||
y <- stringList
|
||||
} yield {
|
||||
y
|
||||
}
|
||||
Some(pfns)
|
||||
val stringList : List[String] = commaSeparatedList.trim().split(",").toList.filter(_.nonEmpty)
|
||||
if (stringList.nonEmpty) {
|
||||
val pfns =
|
||||
for {
|
||||
y <- stringList
|
||||
} yield {
|
||||
y.trim()
|
||||
}
|
||||
Some(pfns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug(s"partialFunctionNames is $partialFunctionNames")
|
||||
@ -1047,7 +1142,8 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{
|
||||
|
||||
val apiCollectionIdParam = for {
|
||||
x <- ObpS.param("api-collection-id")
|
||||
} yield x
|
||||
if x.trim.nonEmpty
|
||||
} yield x.trim
|
||||
logger.debug(s"apiCollectionIdParam is $apiCollectionIdParam")
|
||||
|
||||
|
||||
|
||||
@ -129,6 +129,11 @@ object ErrorMessages {
|
||||
|
||||
val createFxCurrencyIssue = "OBP-10050: Cannot create FX currency. "
|
||||
val invalidLogLevel = "OBP-10051: Invalid log level. "
|
||||
val InvalidContentParameter = "OBP-10052: Invalid content parameter. Valid values are: static, dynamic, all"
|
||||
val InvalidTagsParameter = "OBP-10053: Invalid tags parameter. Tags cannot be empty when provided"
|
||||
val InvalidFunctionsParameter = "OBP-10054: Invalid functions parameter. Functions cannot be empty when provided"
|
||||
val InvalidApiCollectionIdParameter = "OBP-10055: Invalid api-collection-id parameter. API collection ID cannot be empty when provided"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ package code.api.ResourceDocs1_4_0
|
||||
import code.api.ResourceDocs1_4_0.ResourceDocs140.ImplementationsResourceDocs
|
||||
import code.api.berlin.group.ConstantsBG
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
|
||||
import code.api.util.ErrorMessages.{InvalidApiCollectionIdParameter, UserHasMissingRoles, UserNotLoggedIn}
|
||||
import code.api.util.{ApiRole, CustomJsonFormats}
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocsJson
|
||||
import code.setup.{DefaultUsers, PropsReset}
|
||||
@ -100,6 +100,52 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with
|
||||
//This should not throw any exceptions
|
||||
responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description))
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with valid parameters", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("content", "static"), ("tags", "Account"))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(200)
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with invalid content parameter", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("content", "invalid"))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(400)
|
||||
responseGetOpenAPI.body.toString should include("OBP-10052")
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with empty tags parameter", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("tags", ""))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(400)
|
||||
responseGetOpenAPI.body.toString should include("OBP-10053")
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with empty functions parameter", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("functions", ""))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(400)
|
||||
responseGetOpenAPI.body.toString should include("OBP-10054")
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with valid multiple tags", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("tags", "Account,Bank"), ("content", "static"))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(200)
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with Account-Firehose tag and static content", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("content", "static"), ("tags", "Account-Firehose"))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(200)
|
||||
}
|
||||
|
||||
scenario("Test OpenAPI endpoint with empty api-collection-id parameter", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET <<? List(("api-collection-id", ""))
|
||||
val responseGetOpenAPI = makeGetRequest(requestGetOpenAPI)
|
||||
responseGetOpenAPI.code should equal(400)
|
||||
responseGetOpenAPI.body.toString should include(InvalidApiCollectionIdParameter)
|
||||
}
|
||||
scenario(s"We will test ${ApiEndpoint1.name} Api -v5.1.0", ApiEndpoint1, VersionOfApi) {
|
||||
val requestGetObp = (ResourceDocsV5_0Request / "resource-docs" / "v5.1.0" / "obp").GET
|
||||
val responseGetObp = makeGetRequest(requestGetObp)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user