eclipse-tractusx/item-relationship-service

[Concept] Improvement of Policy Store API

Opened this issue · 3 comments

As team
I want concept how to improve the policy store api to avoid certain problems
so that we could provide a proper and suitable policy handling over the policy store api

Link

Hints / Details

  • Create policy with policyId
  • Add policyId to BPNLs []
  • Define default policy
  • Removal of policy from BPNL
  • Deletion of policy from BPNL[]

Acceptance Criteria

  • Concept covers (https://github.com/catenax-ng/tx-item-relationship-service/blob/main/docs/concept/TEMPLATE_Concept.md)
    • API creating a unique policy object with a unique id
    • Adding and modifying the validUnit of a policy object
    • Policy Object is unique in the application and only id-reference is stored for BPNLs
    • Adding policies to BPNLs
    • Removing policies from BPNLs
    • Delete policies and remove them from all BPNLs
    • Handling of default policy
    • Validation of all input parameters like policyId or BPNL
    • policyId uses UUID4 format to be validated
    • GET all policy uses pagination

Out of Scope

  • ...

Hints

This is a proposal to be revised

Create a policy

=>

CREATED

{
	"policyId": "policy1",
	"bpnls": [ <list of bpnls> ]
}

validation: if any validation error occurs nothing should be created and validation errors should be returned

  • bpnls are mandatory -> 400
  • bpnls must be valid -> 400
  • validUntil is mandatory -> 400
  • validUntil must be valid- > 400
  • validUntil must be in future -> 400
  • payload is mandatory -> 400
  • payload must contain policyId -> 400
  • policyId must conform to pattern ???to be defined???? -> 400
  • payload must be schema conform -> 400
  • policy with this policyId already exists -> 409, CONFLICT

other error responses return status and list of error messages

Updating a policy

Update a policy completely

PUT will remove the policy with the given ID from all not specified BPNLs (because PUT is defined as REPLACE).

PUT /irs/policies/policy1

{
  "bpnls": ["BPNL1234567890AB", "BPNL1234567890AB"],
  "validUntil": "2025-12-12T23:59:59.999Z",  
  "payload": {
    "@context": {
      "odrl": "http://www.w3.org/ns/odrl/2/"
    },
    "@id": "policy1",
    "@type": "PolicyDefinitionRequestDto",
    "policy": {
      "@type": "Policy",
      "odrl:permission": [
        {
          "odrl:action": "USE",
          "odrl:constraint": {
            "odrl:and": [
              {
                "odrl:leftOperand": "Membership",
                "odrl:operator": {
                  "@id": "odrl:eq"
                },
                "odrl:rightOperand": "active"
              },
              {
                "odrl:leftOperand": "PURPOSE",
                "odrl:operator": {
                  "@id": "odrl:eq"
                },
                "odrl:rightOperand": "ID 3.1 Trace"
              }
            ]
          }
        }
      ]
    }
  }
}

validation: if any validation error occurs nothing should be created and validation errors should be returned

  • bpnls are mandatory -> 400
  • bpnls must be valid -> 400
  • validUntil is mandatory -> 400
  • validUntil must be valid -> 400
  • validUntil must be in future -> 400
  • payload is mandatory -> 400
  • payload must contain policyId -> 400
  • policyId must conform to pattern ???to be defined????
  • payload must be schema conform -> 400
  • policyId in path does not match policyId in given payload -> 400

other error responses return status and list of error messages

Update a policies' validUntil

PATCH /irs/policies/<policyId>

with body

{
	validUntil: "<new validUntil>"
}

validation:

  • validUntil is mandatory -> 400
  • validUntil must be valid -> 400
  • validUntil must be in future -> 400
  • policy with ID must exist -> 404, NOT FOUND

other error responses return status and list of error messages

Getting information about policies

Get all policies

as currently implemented:

GET /irs/policies

=>

{
	"BPNL1234567890EE": [
		<list of policies as full JSON>
	],
	"BPNL1234567890FF": [
		<list of policies as full JSON>
	],
	...
}

Get policies for BPNLs

as currently implemented:

GET /irs/policies?businessPartnerNumbers=BPNL1234567890EE&businessPartnerNumbers=BPNL1234567890FF

=>

{
	"BPNL1234567890EE": [
		<list of policies as full JSON>
	],
	"BPNL1234567890FF": [
		<list of policies as full JSON>
	]
}

Get policy by policyId

GET /irs/policies/policy1

{
  "bpnls": ["BPNL1234567890AB", "BPNL1234567890AB"],
  "validUntil": "2025-12-12T23:59:59.999Z",  
  "payload": {
    "@context": {
      "odrl": "http://www.w3.org/ns/odrl/2/"
    },
    "@id": "policy1",
    "@type": "PolicyDefinitionRequestDto",
    "policy": {
      "@type": "Policy",
      "odrl:permission": [
        {
          "odrl:action": "USE",
          "odrl:constraint": {
            "odrl:and": [
              {
                "odrl:leftOperand": "Membership",
                "odrl:operator": {
                  "@id": "odrl:eq"
                },
                "odrl:rightOperand": "active"
              },
              {
                "odrl:leftOperand": "PURPOSE",
                "odrl:operator": {
                  "@id": "odrl:eq"
                },
                "odrl:rightOperand": "ID 3.1 Trace"
              }
            ]
          }
        }
      ]
    }
  }
}

when policy does not exist -> 404

Get the validUntil of a policy

GET /irs/policies/<policyId>?fields=validUntil

=>

OK
{
	validUntil: "<valid until date>"
}

validation:

  • when fields contains unsupported fields -> 400
  • when policy does not exist -> 404

Get the payload of a policy

GET /irs/policies/<policyId>?fields=payload

=>

OK
{
	payload: <the policy payload>
}

validation:

  • when fields contains unsupported fields -> 400
  • when policy does not exist -> 404

Get BPNL - policy associations

Get the BPNLs for a policy

GET /irs/policies/<policyId>?fields=bpnls

=>

OK
{
	bpnls: [ <list of BPNLs> ]
}

validation:

  • when fields contains unsupported fields -> 400
  • when policy does not exist -> 404

Get the policyIds for a BPNL

GET /irs/bpnls/<BPNL>?fields=policyIds

=>

OK
{
	policyIds: [ <list of policyIds> ]
}

validation:

  • when fields contains unsupported fields -> 400
  • when BPNL is invalid -> 400
  • when BPNL not found -> 404 ????
  • when policy does not exist -> 404

Update BPNL - policy associations

Remove policy from BPNL

Remove policy from BPNL

DELETE /irs/policies/<thePolicyId>/bpnl/<theBPNL>

disadvantages:

  • only 1:1 delete
  • requires another endpoint for adding BPNL to a polidy

advantage:

  • easy error handling

validation:

  • when policy does not exist -> 404
  • when BPNL is invalid -> 400
  • when BPNL not found -> 404 ????

the following PATCH requests would be more flexible:

Associate policyIds to a BPNL

PATCH /irs/bpnls/<BPNL>

body for automatic addition / removal:

{
	policyIds: [ <list of policyIds> ]
}

body for for defined addition / removal:

{
	policyIdsToAdd: [ <list of policyIds> ],
	policyIdsToRemove: [ <list of policyIds> ] 
}

validation:

  • when BPNL is invalid -> 400
  • when BPNL does not exist -> 404 ????
  • when neither policyIds nor policyIdsToAdd nor policyIdsToRemove is given -> 400
  • when both policyIds and one of policyIdsToAdd or policyIdsToRemove is given -> 400
  • when policyIds do not conform to pattern ????? -> 400

in both cases response:

{
	policyIdsAdded: [ <list of policyIds> ],
	policyIdsRemoved: [ <list of policyIds> ],
    errors: [ ... ]
}

Associate BPNLs to a policy

PATCH /irs/policies/<policyId>

body for automatic addition / removal:

{
	bpnls: [ <list of BPNLs> ]  
}

body for for defined addition / removal:

{
	bpnlsToAdd: [ <list of BPNLs> ],  
	bpnlsToRemove: [ <list of BPNLs> ]
}

validation:

  • when policy does not exist -> 404
  • when some BPNLs are invalid -> 400
  • when some BPNLs do not exist -> 404 ????
  • when neither bpnls nor bpnlsToAdd nor bpnlsToRemove is given -> 400
  • when both bpnls and one of bpnlsToAdd or bpnlsToRemove is given -> 400

in both cases response:

{
	bpnlsAdded: [ <list of policyIds> ],
	bpnlsRemoved: [ <list of policyIds> ],
    errors: [...]
}

Delete a policy

Deletes policy from all BPNLs

DELETE /irs/policies/<thePolicyId>

validation:

  • policy does not exist -> 404

response:

OK

{
	bpnlsRemoved: [ <list of policyIds> ]
}

Default policies

Create a default policy

Same as "Create a policy" but
with dedicated URL POST /irs/default-policies/default-policy-1
and without attribute "bpnls".

Update a default policy completely

Same as "Update a policy completely" but
with dedicated URL PUT /irs/default-policies/default-policy-1
and without attribute "bpnls".

Update a default policies' validUntil

Same as "Update a policies' validUntil" but
with dedicated URL PATCH /irs/default-policies/default-policy-1.

Delete a default policy

Same as "Delete a policy" but
with dedicated URL DELETE /irs/default-policies/default-policy-1.

  • link to this discussions page: #562

  • for discussion of #561

todo:

for comparison:

design goals:

  • simplify error handling as much as possible
  • use restful urls
  • consistency
  • remove ambiguity
  • make API mostly self-explanatory (using standard structures, good naming of resources, params, attributs,...)
  • validation before writes
  • allow to update single fields
  • allow to specify associations in a dedicated way
  • do not allow n:m association updates in one request (use multiple requests instead e.g. multiple 1:m update requests)
dsmf commented

@mkanal "Policy Object is unique in the application and only id-reference is stored for BPNLs" would a lot more than just API change, it involves changes to the underlying data storage or even a change of technology to relational DB. While it might have been good to think about this earlier I am not sure whether it is good to change this now.

dsmf commented

@mkanal for discussion of the API see the following discussions page #562

dsmf commented

@mkanal Another important hint: currently there is no paging for GET all policies request. How many are realistically expected here? Do we need paging?