Merge pull request #560 from Beckn-One/558-router-plugin
558 - feat: Add domain-agnostic routing support for v2 in Onix Adapter Router Plugin
This commit is contained in:
101
CONFIG.md
101
CONFIG.md
@@ -622,9 +622,43 @@ routingRules:
|
|||||||
|
|
||||||
#### `domain`
|
#### `domain`
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Required**: Yes
|
**Required**: Conditional (Required for v1.x.x, Optional for v2.x.x)
|
||||||
**Description**: Beckn domain identifier (e.g., `retail:1.1.0`, `ONDC:TRV10`, `nic2004:60221`)
|
**Description**: Beckn domain identifier (e.g., `retail:1.1.0`, `ONDC:TRV10`, `nic2004:60221`)
|
||||||
|
|
||||||
|
**Version-Specific Behavior**:
|
||||||
|
- **Beckn Protocol v1.x.x**: Domain is **required**. Each rule must specify a domain, and routing uses domain as a key.
|
||||||
|
- **Beckn Protocol v2.x.x**: Domain is **optional** and ignored during routing. If provided, a warning is logged. All v2 rules are domain-agnostic.
|
||||||
|
- **Conflict Detection**: For v2, multiple rules with the same version and endpoint (regardless of domain) will cause a configuration error.
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
```yaml
|
||||||
|
# Valid v1 rule - domain required
|
||||||
|
- domain: "ONDC:TRV10"
|
||||||
|
version: "1.1.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "http://backend:3000"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
|
||||||
|
# Valid v2 rule - domain optional (omitted)
|
||||||
|
- version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "http://backend:3000"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
|
||||||
|
# Valid v2 rule - domain provided (warning logged, but ignored)
|
||||||
|
- domain: "ONDC:TRV10"
|
||||||
|
version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "http://backend:3000"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
```
|
||||||
|
|
||||||
#### `version`
|
#### `version`
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Required**: Yes
|
**Required**: Yes
|
||||||
@@ -792,6 +826,71 @@ routingRules:
|
|||||||
|
|
||||||
**Behavior**: All endpoints route to exactly `http://backend:3000/webhook` without appending the endpoint name.
|
**Behavior**: All endpoints route to exactly `http://backend:3000/webhook` without appending the endpoint name.
|
||||||
|
|
||||||
|
#### Example 5: Beckn Protocol v2 Domain-Agnostic Routing
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
routingRules:
|
||||||
|
# v2 rule without domain (recommended)
|
||||||
|
- version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "https://gateway.example.com/v2"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
- select
|
||||||
|
- init
|
||||||
|
- confirm
|
||||||
|
|
||||||
|
# v1 rules still require domain
|
||||||
|
- domain: "ONDC:TRV10"
|
||||||
|
version: "1.1.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "https://gateway.example.com/v1/trv"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
```
|
||||||
|
|
||||||
|
**Behavior**:
|
||||||
|
- v2 requests (version `2.0.0`) route to gateway regardless of domain in request
|
||||||
|
- v1 requests (version `1.1.0`) route based on domain matching
|
||||||
|
- Domain field is ignored for v2 routing decisions
|
||||||
|
|
||||||
|
#### Example 6: v2 Conflict Detection
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# INVALID CONFIGURATION - Will fail at startup
|
||||||
|
routingRules:
|
||||||
|
- domain: "ONDC:TRV10"
|
||||||
|
version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "https://backend-a.com"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
|
||||||
|
- domain: "ONDC:TRV11" # Different domain, but same version and endpoint
|
||||||
|
version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "https://backend-b.com"
|
||||||
|
endpoints:
|
||||||
|
- search # ERROR: Duplicate v2 rule for 'search' endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error**: Configuration will fail with: `duplicate endpoint 'search' found for version 2.0.0. For v2.x.x, domain is ignored, so you can only define each endpoint once per version. Please remove the duplicate rule`
|
||||||
|
|
||||||
|
**Fix**: For v2, use a single rule per endpoint since domain is ignored:
|
||||||
|
```yaml
|
||||||
|
routingRules:
|
||||||
|
- version: "2.0.0"
|
||||||
|
targetType: "url"
|
||||||
|
target:
|
||||||
|
url: "https://unified-backend.com"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Deployment Scenarios
|
## Deployment Scenarios
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ The **Beckn Protocol** is an open protocol that enables location-aware, local co
|
|||||||
|
|
||||||
#### 3. **Plugin Types**
|
#### 3. **Plugin Types**
|
||||||
- **Cache**: Redis-based response caching
|
- **Cache**: Redis-based response caching
|
||||||
- **Router**: YAML-based routing rules engine for request forwarding
|
- **Router**: YAML-based routing rules engine for request forwarding (supports domain-agnostic routing for Beckn v2.x.x)
|
||||||
- **Signer**: Ed25519 digital signature creation for outgoing requests
|
- **Signer**: Ed25519 digital signature creation for outgoing requests
|
||||||
- **SignValidator**: Ed25519 signature validation for incoming requests
|
- **SignValidator**: Ed25519 signature validation for incoming requests
|
||||||
- **SchemaValidator**: JSON schema validation
|
- **SchemaValidator**: JSON schema validation
|
||||||
|
|||||||
28
SETUP.md
28
SETUP.md
@@ -865,29 +865,39 @@ router:
|
|||||||
|
|
||||||
### Routing Rules Configuration
|
### Routing Rules Configuration
|
||||||
|
|
||||||
|
**For complete routing configuration documentation including v2 domain-agnostic routing, see [CONFIG.md - Routing Configuration](CONFIG.md#routing-configuration).**
|
||||||
|
|
||||||
|
Basic example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
routingRules:
|
routingRules:
|
||||||
|
# v1.x.x - domain is required
|
||||||
- domain: "ONDC:RET10"
|
- domain: "ONDC:RET10"
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
targetType: "url" # or "publisher"
|
targetType: "url" # or "publisher"
|
||||||
target:
|
target:
|
||||||
url: "https://seller.example.com/beckn"
|
url: "https://seller.example.com/beckn"
|
||||||
# OR for async
|
|
||||||
# queueName: "retail_queue"
|
|
||||||
# routingKey: "retail.*"
|
|
||||||
endpoints:
|
endpoints:
|
||||||
- search
|
- search
|
||||||
- select
|
- select
|
||||||
- init
|
- init
|
||||||
- confirm
|
- confirm
|
||||||
headers: # Optional additional headers
|
|
||||||
X-Custom-Header: "value"
|
# v2.x.x - domain is optional (domain-agnostic routing)
|
||||||
timeout: 60 # seconds
|
- version: "2.0.0"
|
||||||
retryPolicy:
|
targetType: "url"
|
||||||
maxRetries: 3
|
target:
|
||||||
backoff: exponential
|
url: "https://seller.example.com/v2/beckn"
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
- select
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Key Points**:
|
||||||
|
- **v1.x.x**: Domain field is required and used for routing
|
||||||
|
- **v2.x.x**: Domain field is optional and ignored (domain-agnostic)
|
||||||
|
- See CONFIG.md for target types: `url`, `bpp`, `bap`, `publisher`
|
||||||
|
|
||||||
### Processing Steps
|
### Processing Steps
|
||||||
|
|
||||||
Available steps for configuration:
|
Available steps for configuration:
|
||||||
|
|||||||
@@ -92,14 +92,23 @@ func (r *Router) loadRules(configPath string) error {
|
|||||||
}
|
}
|
||||||
// Build the optimized rule map
|
// Build the optimized rule map
|
||||||
for _, rule := range config.RoutingRules {
|
for _, rule := range config.RoutingRules {
|
||||||
|
// For v2.x.x, warn if domain is provided and normalize to wildcard "*"
|
||||||
|
domain := rule.Domain
|
||||||
|
if isV2Version(rule.Version) {
|
||||||
|
if domain != "" {
|
||||||
|
fmt.Printf("WARNING: Domain field '%s' is not needed for version %s and will be ignored. Consider removing it from your config.\n", domain, rule.Version)
|
||||||
|
}
|
||||||
|
domain = "*"
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize domain map if not exists
|
// Initialize domain map if not exists
|
||||||
if _, ok := r.rules[rule.Domain]; !ok {
|
if _, ok := r.rules[domain]; !ok {
|
||||||
r.rules[rule.Domain] = make(map[string]map[string]*model.Route)
|
r.rules[domain] = make(map[string]map[string]*model.Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize version map if not exists
|
// Initialize version map if not exists
|
||||||
if _, ok := r.rules[rule.Domain][rule.Version]; !ok {
|
if _, ok := r.rules[domain][rule.Version]; !ok {
|
||||||
r.rules[rule.Domain][rule.Version] = make(map[string]*model.Route)
|
r.rules[domain][rule.Version] = make(map[string]*model.Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all endpoints for this rule
|
// Add all endpoints for this rule
|
||||||
@@ -137,7 +146,13 @@ func (r *Router) loadRules(configPath string) error {
|
|||||||
URL: parsedURL,
|
URL: parsedURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.rules[rule.Domain][rule.Version][endpoint] = route
|
// Check for conflicting v2 rules
|
||||||
|
if isV2Version(rule.Version) {
|
||||||
|
if _, exists := r.rules[domain][rule.Version][endpoint]; exists {
|
||||||
|
return fmt.Errorf("duplicate endpoint '%s' found for version %s. For v2.x.x, domain is ignored, so you can only define each endpoint once per version. Please remove the duplicate rule", endpoint, rule.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.rules[domain][rule.Version][endpoint] = route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,9 +162,14 @@ func (r *Router) loadRules(configPath string) error {
|
|||||||
// validateRules performs basic validation on the loaded routing rules.
|
// validateRules performs basic validation on the loaded routing rules.
|
||||||
func validateRules(rules []routingRule) error {
|
func validateRules(rules []routingRule) error {
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
// Ensure domain, version, and TargetType are present
|
// Ensure version and TargetType are present
|
||||||
if rule.Domain == "" || rule.Version == "" || rule.TargetType == "" {
|
if rule.Version == "" || rule.TargetType == "" {
|
||||||
return fmt.Errorf("invalid rule: domain, version, and targetType are required")
|
return fmt.Errorf("invalid rule: version and targetType are required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain is required only for v1.x.x
|
||||||
|
if !isV2Version(rule.Version) && rule.Domain == "" {
|
||||||
|
return fmt.Errorf("invalid rule: domain is required for version %s", rule.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate based on TargetType
|
// Validate based on TargetType
|
||||||
@@ -197,19 +217,34 @@ func (r *Router) Route(ctx context.Context, url *url.URL, body []byte) (*model.R
|
|||||||
// Extract the endpoint from the URL
|
// Extract the endpoint from the URL
|
||||||
endpoint := path.Base(url.Path)
|
endpoint := path.Base(url.Path)
|
||||||
|
|
||||||
|
// For v2.x.x, ignore domain and use wildcard; for v1.x.x, use actual domain
|
||||||
|
domain := requestBody.Context.Domain
|
||||||
|
if isV2Version(requestBody.Context.Version) {
|
||||||
|
domain = "*"
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup route in the optimized map
|
// Lookup route in the optimized map
|
||||||
domainRules, ok := r.rules[requestBody.Context.Domain]
|
domainRules, ok := r.rules[domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
if domain == "*" {
|
||||||
|
return nil, fmt.Errorf("no routing rules found for version %s", requestBody.Context.Version)
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("no routing rules found for domain %s", requestBody.Context.Domain)
|
return nil, fmt.Errorf("no routing rules found for domain %s", requestBody.Context.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
versionRules, ok := domainRules[requestBody.Context.Version]
|
versionRules, ok := domainRules[requestBody.Context.Version]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
if domain == "*" {
|
||||||
|
return nil, fmt.Errorf("no routing rules found for version %s", requestBody.Context.Version)
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("no routing rules found for domain %s version %s", requestBody.Context.Domain, requestBody.Context.Version)
|
return nil, fmt.Errorf("no routing rules found for domain %s version %s", requestBody.Context.Domain, requestBody.Context.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
route, ok := versionRules[endpoint]
|
route, ok := versionRules[endpoint]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
if domain == "*" {
|
||||||
|
return nil, fmt.Errorf("endpoint '%s' is not supported for version %s in routing config", endpoint, requestBody.Context.Version)
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("endpoint '%s' is not supported for domain %s and version %s in routing config",
|
return nil, fmt.Errorf("endpoint '%s' is not supported for domain %s and version %s in routing config",
|
||||||
endpoint, requestBody.Context.Domain, requestBody.Context.Version)
|
endpoint, requestBody.Context.Domain, requestBody.Context.Version)
|
||||||
}
|
}
|
||||||
@@ -252,3 +287,8 @@ func joinPath(u *url.URL, endpoint string) string {
|
|||||||
}
|
}
|
||||||
return path.Join(u.Path, endpoint)
|
return path.Join(u.Path, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isV2Version checks if the version is 2.x.x
|
||||||
|
func isV2Version(version string) bool {
|
||||||
|
return strings.HasPrefix(version, "2.")
|
||||||
|
}
|
||||||
@@ -124,7 +124,7 @@ func TestLoadRules(t *testing.T) {
|
|||||||
// Expected router.rules map structure based on the yaml.
|
// Expected router.rules map structure based on the yaml.
|
||||||
expectedRules := map[string]map[string]map[string]*model.Route{
|
expectedRules := map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://mock_gateway.com/v2/ondc/search")},
|
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://mock_gateway.com/v2/ondc/search")},
|
||||||
"init": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/init")},
|
"init": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/init")},
|
||||||
"select": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/select")},
|
"select": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/select")},
|
||||||
@@ -291,7 +291,7 @@ func TestValidateRulesFailure(t *testing.T) {
|
|||||||
Endpoints: []string{"search", "select"},
|
Endpoints: []string{"search", "select"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: "invalid rule: domain, version, and targetType are required",
|
wantErr: "invalid rule: domain is required for version 1.0.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Missing version",
|
name: "Missing version",
|
||||||
@@ -305,7 +305,7 @@ func TestValidateRulesFailure(t *testing.T) {
|
|||||||
Endpoints: []string{"search", "select"},
|
Endpoints: []string{"search", "select"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: "invalid rule: domain, version, and targetType are required",
|
wantErr: "invalid rule: version and targetType are required",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Missing targetType",
|
name: "Missing targetType",
|
||||||
@@ -319,7 +319,7 @@ func TestValidateRulesFailure(t *testing.T) {
|
|||||||
Endpoints: []string{"search", "select"},
|
Endpoints: []string{"search", "select"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: "invalid rule: domain, version, and targetType are required",
|
wantErr: "invalid rule: version and targetType are required",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid targetType",
|
name: "Invalid targetType",
|
||||||
@@ -438,37 +438,37 @@ func TestRouteSuccess(t *testing.T) {
|
|||||||
name: "Valid domain, version, and endpoint (bpp routing with gateway URL)",
|
name: "Valid domain, version, and endpoint (bpp routing with gateway URL)",
|
||||||
configFile: "bap_caller.yaml",
|
configFile: "bap_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/search",
|
url: "https://example.com/v1/ondc/search",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0"}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid domain, version, and endpoint (bpp routing with bpp_uri)",
|
name: "Valid domain, version, and endpoint (bpp routing with bpp_uri)",
|
||||||
configFile: "bap_caller.yaml",
|
configFile: "bap_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/select",
|
url: "https://example.com/v1/ondc/select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0", "bpp_uri": "https://bpp1.example.com"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0", "bpp_uri": "https://bpp1.example.com"}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid domain, version, and endpoint (url routing)",
|
name: "Valid domain, version, and endpoint (url routing)",
|
||||||
configFile: "bpp_receiver.yaml",
|
configFile: "bpp_receiver.yaml",
|
||||||
url: "https://example.com/v1/ondc/select",
|
url: "https://example.com/v1/ondc/select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0"}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid domain, version, and endpoint (publisher routing)",
|
name: "Valid domain, version, and endpoint (publisher routing)",
|
||||||
configFile: "bpp_receiver.yaml",
|
configFile: "bpp_receiver.yaml",
|
||||||
url: "https://example.com/v1/ondc/search",
|
url: "https://example.com/v1/ondc/search",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0"}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid domain, version, and endpoint (bap routing with bap_uri)",
|
name: "Valid domain, version, and endpoint (bap routing with bap_uri)",
|
||||||
configFile: "bpp_caller.yaml",
|
configFile: "bpp_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/on_select",
|
url: "https://example.com/v1/ondc/on_select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0", "bap_uri": "https://bap1.example.com"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0", "bap_uri": "https://bap1.example.com"}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid domain, version, and endpoint (bpp routing with bpp_uri)",
|
name: "Valid domain, version, and endpoint (bpp routing with bpp_uri)",
|
||||||
configFile: "bap_receiver.yaml",
|
configFile: "bap_receiver.yaml",
|
||||||
url: "https://example.com/v1/ondc/on_select",
|
url: "https://example.com/v1/ondc/on_select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0", "bpp_uri": "https://bpp1.example.com"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0", "bpp_uri": "https://bpp1.example.com"}}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,35 +504,35 @@ func TestRouteFailure(t *testing.T) {
|
|||||||
name: "Unsupported endpoint",
|
name: "Unsupported endpoint",
|
||||||
configFile: "bpp_receiver.yaml",
|
configFile: "bpp_receiver.yaml",
|
||||||
url: "https://example.com/v1/ondc/unsupported",
|
url: "https://example.com/v1/ondc/unsupported",
|
||||||
body: `{"context": {"domain": "ONDC:TRV11", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV11", "version": "1.1.0"}}`,
|
||||||
wantErr: "endpoint 'unsupported' is not supported for domain ONDC:TRV11 and version 2.0.0",
|
wantErr: "endpoint 'unsupported' is not supported for domain ONDC:TRV11 and version 1.1.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "No matching rule",
|
name: "No matching rule",
|
||||||
configFile: "bpp_receiver.yaml",
|
configFile: "bpp_receiver.yaml",
|
||||||
url: "https://example.com/v1/ondc/select",
|
url: "https://example.com/v1/ondc/select",
|
||||||
body: `{"context": {"domain": "ONDC:SRV11", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:SRV11", "version": "1.1.0"}}`,
|
||||||
wantErr: "no routing rules found for domain ONDC:SRV11",
|
wantErr: "no routing rules found for domain ONDC:SRV11",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Missing bap_uri for bap routing",
|
name: "Missing bap_uri for bap routing",
|
||||||
configFile: "bpp_caller.yaml",
|
configFile: "bpp_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/on_search",
|
url: "https://example.com/v1/ondc/on_search",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0"}}`,
|
||||||
wantErr: "could not determine destination for endpoint 'on_search': neither request contained a BAP URI nor was a default URL configured in routing rules",
|
wantErr: "could not determine destination for endpoint 'on_search': neither request contained a BAP URI nor was a default URL configured in routing rules",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Missing bpp_uri for bpp routing",
|
name: "Missing bpp_uri for bpp routing",
|
||||||
configFile: "bap_caller.yaml",
|
configFile: "bap_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/select",
|
url: "https://example.com/v1/ondc/select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0"}}`,
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0"}}`,
|
||||||
wantErr: "could not determine destination for endpoint 'select': neither request contained a BPP URI nor was a default URL configured in routing rules",
|
wantErr: "could not determine destination for endpoint 'select': neither request contained a BPP URI nor was a default URL configured in routing rules",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid bpp_uri format in request",
|
name: "Invalid bpp_uri format in request",
|
||||||
configFile: "bap_caller.yaml",
|
configFile: "bap_caller.yaml",
|
||||||
url: "https://example.com/v1/ondc/select",
|
url: "https://example.com/v1/ondc/select",
|
||||||
body: `{"context": {"domain": "ONDC:TRV10", "version": "2.0.0", "bpp_uri": "htp:// invalid-url"}}`, // Invalid scheme (htp instead of http)
|
body: `{"context": {"domain": "ONDC:TRV10", "version": "1.1.0", "bpp_uri": "htp:// invalid-url"}}`, // Invalid scheme (htp instead of http)
|
||||||
wantErr: `invalid BPP URI - htp:// invalid-url in request body for select: parse "htp:// invalid-url": invalid character " " in host name`,
|
wantErr: `invalid BPP URI - htp:// invalid-url in request body for select: parse "htp:// invalid-url": invalid character " " in host name`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -565,7 +565,7 @@ func TestExcludeAction(t *testing.T) {
|
|||||||
configFile: "exclude_action_true.yaml",
|
configFile: "exclude_action_true.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc")},
|
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc")},
|
||||||
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc")},
|
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc")},
|
||||||
},
|
},
|
||||||
@@ -577,7 +577,7 @@ func TestExcludeAction(t *testing.T) {
|
|||||||
configFile: "exclude_action_false.yaml",
|
configFile: "exclude_action_false.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/search")},
|
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/search")},
|
||||||
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/init")},
|
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/init")},
|
||||||
},
|
},
|
||||||
@@ -589,7 +589,7 @@ func TestExcludeAction(t *testing.T) {
|
|||||||
configFile: "exclude_action_default.yaml",
|
configFile: "exclude_action_default.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/search")},
|
"search": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/search")},
|
||||||
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/init")},
|
"init": {TargetType: targetTypeURL, URL: parseURL(t, "https://services-backend.com/v2/ondc/init")},
|
||||||
},
|
},
|
||||||
@@ -630,7 +630,7 @@ func TestExcludeActionWithNonURLTargetTypes(t *testing.T) {
|
|||||||
configFile: "exclude_action_bpp.yaml",
|
configFile: "exclude_action_bpp.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeBPP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/search")},
|
"search": {TargetType: targetTypeBPP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/search")},
|
||||||
"init": {TargetType: targetTypeBPP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/init")},
|
"init": {TargetType: targetTypeBPP, URL: parseURL(t, "https://mock_bpp.com/v2/ondc/init")},
|
||||||
},
|
},
|
||||||
@@ -642,7 +642,7 @@ func TestExcludeActionWithNonURLTargetTypes(t *testing.T) {
|
|||||||
configFile: "exclude_action_bap.yaml",
|
configFile: "exclude_action_bap.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bap.com/v2/ondc/search")},
|
"search": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bap.com/v2/ondc/search")},
|
||||||
"init": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bap.com/v2/ondc/init")},
|
"init": {TargetType: targetTypeBAP, URL: parseURL(t, "https://mock_bap.com/v2/ondc/init")},
|
||||||
},
|
},
|
||||||
@@ -654,7 +654,7 @@ func TestExcludeActionWithNonURLTargetTypes(t *testing.T) {
|
|||||||
configFile: "exclude_action_publisher.yaml",
|
configFile: "exclude_action_publisher.yaml",
|
||||||
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
expectedRoutes: map[string]map[string]map[string]*model.Route{
|
||||||
"ONDC:TRV10": {
|
"ONDC:TRV10": {
|
||||||
"2.0.0": {
|
"1.1.0": {
|
||||||
"search": {TargetType: targetTypePublisher, PublisherID: "test_topic", URL: nil},
|
"search": {TargetType: targetTypePublisher, PublisherID: "test_topic", URL: nil},
|
||||||
"init": {TargetType: targetTypePublisher, PublisherID: "test_topic", URL: nil},
|
"init": {TargetType: targetTypePublisher, PublisherID: "test_topic", URL: nil},
|
||||||
},
|
},
|
||||||
@@ -682,3 +682,113 @@ func TestExcludeActionWithNonURLTargetTypes(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TestV2RouteSuccess tests v2 routing with domain-agnostic behavior
|
||||||
|
func TestV2RouteSuccess(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
configFile string
|
||||||
|
url string
|
||||||
|
body string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "v2 BAP caller - domain ignored",
|
||||||
|
configFile: "v2_bap_caller.yaml",
|
||||||
|
url: "https://example.com/v2/search",
|
||||||
|
body: `{"context": {"domain": "any_domain", "version": "2.0.0"}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v2 BPP receiver - domain ignored",
|
||||||
|
configFile: "v2_bpp_receiver.yaml",
|
||||||
|
url: "https://example.com/v2/select",
|
||||||
|
body: `{"context": {"domain": "different_domain", "version": "2.0.0"}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v2 request without domain field",
|
||||||
|
configFile: "v2_bap_caller.yaml",
|
||||||
|
url: "https://example.com/v2/search",
|
||||||
|
body: `{"context": {"version": "2.0.0"}}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
router, _, rulesFilePath := setupRouter(t, tt.configFile)
|
||||||
|
defer os.RemoveAll(filepath.Dir(rulesFilePath))
|
||||||
|
|
||||||
|
parsedURL, _ := url.Parse(tt.url)
|
||||||
|
_, err := router.Route(ctx, parsedURL, []byte(tt.body))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("router.Route() = %v, want nil (domain should be ignored for v2)", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestV2ConflictingRules tests that conflicting v2 rules are detected at load time
|
||||||
|
func TestV2ConflictingRules(t *testing.T) {
|
||||||
|
router := &Router{
|
||||||
|
rules: make(map[string]map[string]map[string]*model.Route),
|
||||||
|
}
|
||||||
|
|
||||||
|
configDir := t.TempDir()
|
||||||
|
conflictingConfig := `routingRules:
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: bap
|
||||||
|
endpoints:
|
||||||
|
- on_search
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: bap
|
||||||
|
endpoints:
|
||||||
|
- on_search
|
||||||
|
`
|
||||||
|
rulesPath := filepath.Join(configDir, "conflicting_rules.yaml")
|
||||||
|
if err := os.WriteFile(rulesPath, []byte(conflictingConfig), 0644); err != nil {
|
||||||
|
t.Fatalf("WriteFile() err = %v, want nil", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(configDir)
|
||||||
|
|
||||||
|
err := router.loadRules(rulesPath)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("loadRules() with conflicting v2 rules should return error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedErr := "duplicate endpoint 'on_search' found for version 2.0.0"
|
||||||
|
if err != nil && !strings.Contains(err.Error(), expectedErr) {
|
||||||
|
t.Errorf("loadRules() error = %v, want error containing %q", err, expectedErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestV1DomainRequired tests that domain is required for v1 configs
|
||||||
|
func TestV1DomainRequired(t *testing.T) {
|
||||||
|
router := &Router{
|
||||||
|
rules: make(map[string]map[string]map[string]*model.Route),
|
||||||
|
}
|
||||||
|
|
||||||
|
configDir := t.TempDir()
|
||||||
|
v1ConfigWithoutDomain := `routingRules:
|
||||||
|
- version: 1.0.0
|
||||||
|
targetType: bap
|
||||||
|
endpoints:
|
||||||
|
- on_search
|
||||||
|
`
|
||||||
|
rulesPath := filepath.Join(configDir, "v1_no_domain.yaml")
|
||||||
|
if err := os.WriteFile(rulesPath, []byte(v1ConfigWithoutDomain), 0644); err != nil {
|
||||||
|
t.Fatalf("WriteFile() err = %v, want nil", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(configDir)
|
||||||
|
|
||||||
|
err := router.loadRules(rulesPath)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("loadRules() with v1 config without domain should fail, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedErr := "invalid rule: domain is required for version 1.0.0"
|
||||||
|
if err != nil && !strings.Contains(err.Error(), expectedErr) {
|
||||||
|
t.Errorf("loadRules() error = %v, want error containing %q", err, expectedErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bpp
|
targetType: bpp
|
||||||
target:
|
target:
|
||||||
url: https://gateway.example.com
|
url: https://gateway.example.com
|
||||||
endpoints:
|
endpoints:
|
||||||
- search
|
- search
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bpp
|
targetType: bpp
|
||||||
endpoints:
|
endpoints:
|
||||||
- select
|
- select
|
||||||
@@ -16,7 +16,7 @@ routingRules:
|
|||||||
- status
|
- status
|
||||||
- cancel
|
- cancel
|
||||||
- domain: ONDC:TRV12
|
- domain: ONDC:TRV12
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bpp
|
targetType: bpp
|
||||||
endpoints:
|
endpoints:
|
||||||
- select
|
- select
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend/trv/v1
|
url: https://services-backend/trv/v1
|
||||||
@@ -12,7 +12,7 @@ routingRules:
|
|||||||
- on_update
|
- on_update
|
||||||
- on_cancel
|
- on_cancel
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: publisher
|
targetType: publisher
|
||||||
target:
|
target:
|
||||||
publisherId: trv_topic_id1
|
publisherId: trv_topic_id1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bap
|
targetType: bap
|
||||||
endpoints:
|
endpoints:
|
||||||
- on_search
|
- on_search
|
||||||
@@ -11,7 +11,7 @@ routingRules:
|
|||||||
- on_update
|
- on_update
|
||||||
- on_cancel
|
- on_cancel
|
||||||
- domain: ONDC:TRV11
|
- domain: ONDC:TRV11
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bap
|
targetType: bap
|
||||||
endpoints:
|
endpoints:
|
||||||
- on_search
|
- on_search
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend/trv/v1
|
url: https://services-backend/trv/v1
|
||||||
@@ -11,14 +11,14 @@ routingRules:
|
|||||||
- status
|
- status
|
||||||
- cancel
|
- cancel
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: publisher
|
targetType: publisher
|
||||||
target:
|
target:
|
||||||
publisherId: trv_topic_id1
|
publisherId: trv_topic_id1
|
||||||
endpoints:
|
endpoints:
|
||||||
- search
|
- search
|
||||||
- domain: ONDC:TRV11
|
- domain: ONDC:TRV11
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend/trv/v1
|
url: https://services-backend/trv/v1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bap
|
targetType: bap
|
||||||
target:
|
target:
|
||||||
url: https://mock_bap.com/v2/ondc
|
url: https://mock_bap.com/v2/ondc
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bpp
|
targetType: bpp
|
||||||
target:
|
target:
|
||||||
url: https://mock_bpp.com/v2/ondc
|
url: https://mock_bpp.com/v2/ondc
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend.com/v2/ondc
|
url: https://services-backend.com/v2/ondc
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend.com/v2/ondc
|
url: https://services-backend.com/v2/ondc
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: publisher
|
targetType: publisher
|
||||||
target:
|
target:
|
||||||
publisherId: test_topic
|
publisherId: test_topic
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://services-backend.com/v2/ondc
|
url: https://services-backend.com/v2/ondc
|
||||||
|
|||||||
15
pkg/plugin/implementation/router/testData/v2_bap_caller.yaml
Normal file
15
pkg/plugin/implementation/router/testData/v2_bap_caller.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
routingRules:
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: bpp
|
||||||
|
target:
|
||||||
|
url: https://gateway.example.com
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: bpp
|
||||||
|
endpoints:
|
||||||
|
- select
|
||||||
|
- init
|
||||||
|
- confirm
|
||||||
|
- status
|
||||||
|
- cancel
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
routingRules:
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: url
|
||||||
|
target:
|
||||||
|
url: https://services-backend/trv/v2
|
||||||
|
endpoints:
|
||||||
|
- select
|
||||||
|
- init
|
||||||
|
- confirm
|
||||||
|
- status
|
||||||
|
- cancel
|
||||||
|
- version: 2.0.0
|
||||||
|
targetType: publisher
|
||||||
|
target:
|
||||||
|
publisherId: trv_topic_v2
|
||||||
|
endpoints:
|
||||||
|
- search
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
# testData/all_route_types.yaml
|
# testData/all_route_types.yaml
|
||||||
routingRules:
|
routingRules:
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: url
|
targetType: url
|
||||||
target:
|
target:
|
||||||
url: https://mock_gateway.com/v2/ondc
|
url: https://mock_gateway.com/v2/ondc
|
||||||
endpoints:
|
endpoints:
|
||||||
- search
|
- search
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bap
|
targetType: bap
|
||||||
target:
|
target:
|
||||||
url: https://mock_bpp.com/v2/ondc
|
url: https://mock_bpp.com/v2/ondc
|
||||||
@@ -16,14 +16,14 @@ routingRules:
|
|||||||
- init
|
- init
|
||||||
- select
|
- select
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: publisher
|
targetType: publisher
|
||||||
target:
|
target:
|
||||||
publisherId: beckn_onix_topic
|
publisherId: beckn_onix_topic
|
||||||
endpoints:
|
endpoints:
|
||||||
- confirm
|
- confirm
|
||||||
- domain: ONDC:TRV10
|
- domain: ONDC:TRV10
|
||||||
version: 2.0.0
|
version: 1.1.0
|
||||||
targetType: bap
|
targetType: bap
|
||||||
target:
|
target:
|
||||||
url: https://mock_bap_gateway.com/v2/ondc
|
url: https://mock_bap_gateway.com/v2/ondc
|
||||||
|
|||||||
Reference in New Issue
Block a user