Ga naar inhoud

Uw eerste wijziging, van begin tot eind

Deze pagina is één lineair script, van een vers access token tot een wijziging die u kunt zien in de Prevu3D Platform, en weer terug. Het gebruikt van begin tot eind de Client Credentials-flow, en elke ID die nodig is komt uit een eerdere API-respons in hetzelfde script: niets om handmatig in te vullen.


  1. Een access token ophalen: authenticeren met Client Credentials
  2. Uw organisatie ontdekken: /oauth/api-info aanroepen voor uw API-URL en organisatie-ID
  3. Navigeren naar een divisie: het eerste kind van uw organisatie
  4. Navigeren naar een site: het eerste kind van die divisie
  5. De site hernoemen: een kleine, duidelijke, omkeerbare wijziging
  6. Bevestigen in de Prevu3D Platform: de finish
  7. De naamswijziging ongedaan maken: geen sporen achterlaten
  • Doorloop eerst de gids Client Credentials-flow. Uw OAuth-applicatie heeft de scopes read:hierarchy en write:hierarchy nodig, en uw servicegebruiker heeft inhoudstoegang en een rol op bewerkingsniveau nodig voor ten minste één site (zie het beveiligingsmodel).
  • Uw organisatie heeft ten minste één divisie nodig met ten minste één site. Deze doorloop navigeert naar de eerste die wordt gevonden.

Endpoint: POST https://cloud-api.prevu3d.com/oauth/token

POST https://cloud-api.prevu3d.com/oauth/token HTTP/1.1
Host: cloud-api.prevu3d.com
Authorization: Basic eW91ci1jbGllbnQtaWQ6eW91ci1jbGllbnQtc2VjcmV0
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
{
"hasError": false,
"access_token": "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3599,
"token_type": "bearer"
}

Bewaar access_token. Zie de gids Client Credentials-flow als dit mislukt.

Endpoint: GET https://cloud-api.prevu3d.com/oauth/api-info

Headers: Authorization: Bearer <access_token>

{
"organization": {
"id": "217ebd23-ec54-4af0-a6d6-4a441a6d1966",
"name": "Test Organization"
},
"scopes": ["read:hierarchy", "write:hierarchy"],
"apiUrl": "https://api-ue1.prevu3d.com/realityconnect-api"
}

Bewaar apiUrl en organization.id. Elk verzoek hieronder gebruikt {apiUrl}.

Endpoint: GET {apiUrl}/v1/nodes/{organization_id}/browse

{
"node": { "id": "217ebd23-ec54-4af0-a6d6-4a441a6d1966", "type": "Organization", "...": "..." },
"items": [
{ "id": "3d3b6f2a-9e0a-4b0a-8b0a-1c2d3e4f5a6b", "name": "North America Operations", "type": "Division", "...": "..." }
],
"total": 1
}

Gebruik items[0].id als division_id.

Endpoint: GET {apiUrl}/v1/nodes/{division_id}/browse

{
"node": { "id": "3d3b6f2a-9e0a-4b0a-8b0a-1c2d3e4f5a6b", "type": "Division", "...": "..." },
"items": [
{ "id": "8a1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e", "name": "Chicago Plant", "type": "Site", "...": "..." }
],
"total": 1
}

Gebruik items[0].id als site_id, en bewaar items[0].name (hier "Chicago Plant"); u heeft deze nodig bij stap 7.

Het hernoemen van een node is een kleine, duidelijke, omkeerbare wijziging: het vereist write:hierarchy, raakt verder niets aan en is met één aanroep terug te draaien.

Endpoint: PATCH {apiUrl}/v1/nodes/{site_id}

PATCH https://api-ue1.prevu3d.com/realityconnect-api/v1/nodes/8a1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{ "name": "Chicago Plant (test)" }
{ "id": "8a1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e", "name": "Chicago Plant (test)", "type": "Site", "...": "..." }

Open de Prevu3D Platform, navigeer naar de divisie uit stap 3 en open de site uit stap 4.

U zou nu de nieuwe naam moeten zien, in dit voorbeeld Chicago Plant (test), bovenaan de pagina van de site en in de sitelijst van de divisie. Dat is de finish: een wijziging die volledig via de API is gemaakt, zichtbaar in het product.

Endpoint: PATCH {apiUrl}/v1/nodes/{site_id}

{ "name": "Chicago Plant" }

Stuur de oorspronkelijke naam van de site uit stap 4. De respons, en de Prevu3D Platform, tonen de site nu weer zoals deze was vóór stap 5.

Dit script doorloopt stap 1 t/m 7 in volgorde. Het pauzeert na het hernoemen, zodat u de Prevu3D Platform kunt controleren voordat de wijziging ongedaan wordt gemaakt.

import requests
import base64
client_id = "your-client-id"
client_secret = "your-client-secret"
base_url = "https://cloud-api.prevu3d.com"
# Stap 1: een token ophalen
token_response = requests.post(
f"{base_url}/oauth/token",
data={"grant_type": "client_credentials"},
headers={
"Authorization": f'Basic {base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()}',
"Content-Type": "application/x-www-form-urlencoded",
},
)
token_response.raise_for_status()
access_token = token_response.json()["access_token"]
headers = {"Authorization": f"Bearer {access_token}"}
# Stap 2: de API-URL en organisatie-ID ontdekken
api_info = requests.get(f"{base_url}/oauth/api-info", headers=headers).json()
api_url = api_info["apiUrl"]
organization_id = api_info["organization"]["id"]
# Stap 3: navigeren naar de eerste divisie
divisions = requests.get(f"{api_url}/v1/nodes/{organization_id}/browse", headers=headers).json()
division_id = divisions["items"][0]["id"]
# Stap 4: navigeren naar de eerste site in die divisie
sites = requests.get(f"{api_url}/v1/nodes/{division_id}/browse", headers=headers).json()
site = sites["items"][0]
site_id = site["id"]
original_name = site["name"]
# Stap 5: de site hernoemen
new_name = f"{original_name} (test)"
requests.patch(f"{api_url}/v1/nodes/{site_id}", json={"name": new_name}, headers=headers).raise_for_status()
print(f"Site {site_id} hernoemd naar '{new_name}'.")
print("Open de site nu in de Prevu3D Platform. U zou de nieuwe naam moeten zien.")
input("Druk op Enter zodra u dit heeft bevestigd, om de wijziging ongedaan te maken...")
# Stap 7: de naamswijziging ongedaan maken
requests.patch(f"{api_url}/v1/nodes/{site_id}", json={"name": original_name}, headers=headers).raise_for_status()
print(f"Site {site_id} hersteld naar '{original_name}'.")

De walkthrough hierboven is een happy path: een vers token, een rustig netwerk, niets om opnieuw te proberen. Een script dat langer blijft draaien — een bulkimport, een pollinglus, een grote download — krijgt uiteindelijk te maken met een 429, een access token dat halverwege verloopt, of één aanroep die opnieuw geprobeerd moet worden terwijl de rest van de batch doorgaat. In plaats van elk voorbeeld op deze site op te blazen met dezelfde defensieve code, introduceert deze sectie eenmalig een kleine herbruikbare client; de voorbeelden die deze nodig hebben verwijzen hiernaar terug in plaats van hem te herhalen.

RCAPIClient verpakt de ruwe requests-aanroepen hierboven met drie dingen: het cachet het access token en vernieuwt het automatisch — proactief vóór het verloopt, en reactief bij een 401 — het probeert een 429 opnieuw met behulp van de Retry-After-header (zie Rate Limits) in plaats van een vertraging te raden, en het geeft het op na een maximumaantal pogingen of een maximale verstreken tijd in plaats van eindeloos door te gaan.

import time
import base64
import requests
class RCAPIClient:
"""Token cache + refresh, retry with backoff, and a give-up condition.
Wrap the raw `requests` calls above with this once your integration runs
long enough to hit a rate limit or outlive an access token -- most bulk
imports, polling loops, and long-running downloads do.
"""
def __init__(self, client_id, client_secret, cloud_api_base="https://cloud-api.prevu3d.com"):
self.client_id = client_id
self.client_secret = client_secret
self.cloud_api_base = cloud_api_base
self._access_token = None
self._expires_at = 0 # epoch seconds
def _fetch_token(self):
credentials = base64.b64encode(f"{self.client_id}:{self.client_secret}".encode()).decode()
response = requests.post(
f"{self.cloud_api_base}/oauth/token",
data={"grant_type": "client_credentials"},
headers={"Authorization": f"Basic {credentials}"},
)
response.raise_for_status()
body = response.json()
self._access_token = body["access_token"]
# Refresh a little before the real expiry, not exactly at it.
self._expires_at = time.time() + body["expires_in"] - 60
def _token(self):
if self._access_token is None or time.time() >= self._expires_at:
self._fetch_token()
return self._access_token
def request(self, method, url, max_attempts=6, max_elapsed=300, **kwargs):
"""`requests.request()` plus token refresh, 429 backoff, and a give-up condition."""
start = time.time()
headers = kwargs.pop("headers", {})
for attempt in range(1, max_attempts + 1):
headers["Authorization"] = f"Bearer {self._token()}"
response = requests.request(method, url, headers=headers, **kwargs)
if response.status_code == 401 and attempt == 1:
self._access_token = None # token was rejected outright; force one refresh
continue
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 1))
if attempt == max_attempts or time.time() - start + retry_after > max_elapsed:
response.raise_for_status()
time.sleep(retry_after)
continue
return response
return response
def poll(self, url, is_done, interval=15, max_elapsed=3600):
"""GET `url` through this client until `is_done(body)` or `max_elapsed` seconds pass."""
start = time.time()
while True:
response = self.request("GET", url)
response.raise_for_status()
body = response.json()
if is_done(body):
return body
if time.time() - start >= max_elapsed:
raise TimeoutError(f"Gave up polling {url} after {max_elapsed}s")
time.sleep(interval)

Gebruik deze in plaats van rechtstreeks requests, bijvoorbeeld voor het token en de organisatie-opzoeking uit Stap 1-2 hierboven:

client = RCAPIClient(client_id="your-client-id", client_secret="your-client-secret")
api_info = client.request("GET", "https://cloud-api.prevu3d.com/oauth/api-info").json()

request() remt pas af zodra het een 429 ziet. Als een workload dicht bij de capaciteit van een bucket komt zonder er een te veroorzaken (bijvoorbeeld aanhoudend hoogvolumeverkeer), lees dan X-RateLimit-Remaining en X-RateLimit-Reset uit elke response en vertraag voordat de bucket leeg raakt — zie Rate Limits. poll() bouwt bovenop request() een pollinglus met backoff en opgave-conditie; Verwerking en bewaking gebruikt deze.

U bent van een vers access token naar een wijziging gegaan die u kon zien in de Prevu3D Platform, en weer terug.

  • Uw ID’s vinden: meer manieren om ID’s voor organisatie, divisie, site en andere nodes te achterhalen, naast navigeren.
  • Nodetypen en hiërarchie: de volledige nodeboom die u zojuist heeft doorlopen, en wat elk nodetype kan bevatten.
  • Introductie: het taakgerichte startpunt voor al het andere dat de RealityConnect API kan doen.