Definitie van een aangepaste API
Schema-id: custom-api@1
Machineleesbaar schema: custom-api.schema.json
De canonieke definitie van een aangepaste API (sectie 6.9): een geversioneerd HTTP-contract dat een omgeving publiceert voor systemen buiten het platform, eigendom van een oplossing en meereizend in het pakket daarvan. Een definitie wordt op dezelfde manier gevalideerd, of ze nu uit het Beheercentrum komt, uit een API-aanroep, van een AI-assistent of uit een oplossingsimport.
Structuur
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
logicalName | tekenreeks | ja | Met uitgeversvoorvoegsel, in kleine letters snake_case. Stabiel over versies heen. |
displayName | tekenreeks | ja | De samenvatting van de OpenAPI-operatie. |
publisherPrefix | tekenreeks | ja | Ook een segment van het geserveerde pad. |
version | geheel getal | ja | 1–999. Geserveerd als padsegment v{version}. |
route | tekenreeks | ja | Onder het versiesegment, zonder voorloopslash. Een segment tussen accolades is een padparameter. |
verb | tekenreeks | ja | Get, Post, Put, Patch, Delete. |
script | tekenreeks | ja | De BS Lang die deze API uitvoert. Er is één implementatie, en dit is hem. |
requiredScope | tekenreeks | ja | De scope die de app-registratie van een aanroeper moet hebben. |
description | tekenreeks | null | nee | De beschrijving van de OpenAPI-operatie. |
requestSchema | object | null | nee | Een JSON Schema, bij elke aanroep gecontroleerd. Geweigerd voor een werkwoord zonder body. Null betekent: de getInput-namen van het script zijn het contract (in OpenAPI gepubliceerd; bij een portaalaanroep een gesloten lijst). |
responseSchema | object | null | nee | Een JSON Schema, gepubliceerd in het OpenAPI-document. |
responseContentType | tekenreeks | nee | application/json, text/plain of text/html — waarmee het contract normaal antwoordt, en wat de gegenereerde OpenAPI publiceert. |
isEnabled | booleaans | nee | Een uitgeschakelde definitie wordt opgeslagen en geëxporteerd, en retourneert 404. |
Identiteit is een paar
(logicalName, version) identificeert de API; (publisherPrefix, version, verb, route) is
het adres ervan. par_approve_invoice v1 en v2 zijn één contract op twee leeftijden en
antwoorden naast elkaar terwijl een integratiepartner migreert — dus een tweede definitie
met dezelfde naam en dezelfde versie is een duplicaat, terwijl een definitie met dezelfde
naam en een nieuwe versie de volgende versie is. Twee definities mogen nooit hetzelfde adres
delen, hoe ze ook heten.
Het geserveerde pad
/api/{publisherPrefix}/v{version}/{route}
Vandaag bereikbaar onder een omgeving — /environments/{environmentId}/api/par/v1/invoices
— omdat een client-credentials-token een tenant noemt en niet een van diens omgevingen. De
kortere openbare vorm komt met de Gateway, die een hostnaam aan een omgeving
koppelt.
Wat er wordt uitgevoerd
Eén ding: het script. Een definitie noemt een route en de BS Lang die erop antwoordt,
en er valt verder niets te kiezen. Het script leest het verzoek met getInput, antwoordt
met setOutput of setBody, kiest een status en inhoudstype met setStatus en
setContentType, zet headers met setHeader, bereikt andere tabellen met de
recordfuncties en weigert met throwValidationError.
Vroeger koos een definitie uit vier implementatiesoorten — een directe tabelbewerking, een Automation Flow, een Function en een aangepast plug-inbericht. Drie daarvan konden worden gedefinieerd maar nooit worden uitgevoerd, dus een aanroep antwoordde met 501 en noemde de iteratie waarop hij wachtte, en alleen de vierde draaide. Dat is verdwenen. Een contract waarvan het gedrag de eigen code van de maker is, is eenvoudiger uit te leggen, eenvoudiger te versioneren, en de enige van de vier die iets kon uitdrukken waarop het platform niet had geanticipeerd — en er is geen 501 meer, omdat er geen niet-aangesloten soort meer over is die er een kan opleveren.
Logica die het waard is om tussen twee API's te delen, is een oplossingsscript, op naam geïmporteerd, geen vijfde soort.
Regels die een schema niet kan uitdrukken
Bij het opslaan van de definitie gecontroleerd, naast het schema hierboven:
- Het gedeclareerde
responseContentTypeis er een dat het platform kan serveren. - Een route voor
Read,UpdateofDeletedeclareert{id}— dat is de enige plek waar de id van de record vandaan kan komen. - Een werkwoord zonder body heeft geen aanvraagschema. Een werkwoord met body mag het null laten.
- De aanvraag- en antwoordschema's compileren als JSON Schema.
- Het script is te parsen als BS Lang, en elke module die het importeert, verwijst naar een oplossingsscript.
Voorbeeld
{
"logicalName": "par_create_invoice",
"displayName": "Create an invoice",
"publisherPrefix": "par",
"description": "Creates an invoice from a validated body.",
"version": 1,
"route": "invoices",
"verb": "Post",
"requestSchema": {
"type": "object",
"additionalProperties": false,
"required": ["par_name", "par_amount"],
"properties": {
"par_name": { "type": "string", "maxLength": 200 },
"par_amount": { "type": "number", "exclusiveMinimum": 0 }
}
},
"responseContentType": "application/json",
"requiredScope": "modelapps.write",
"isEnabled": true,
"script": "var id = createRecord('par_invoice', {
par_name: getInput('par_name'),
par_amount: getInput('par_amount')
});
setOutput('id', id);"
}
De body wordt voordat het script draait tegen requestSchema gecontroleerd, dus
getInput leest een vorm die al is gevalideerd in plaats van een vorm waartegen elk script
zich zelf moet verdedigen.
Een invoer kan een object of een lijst zijn
getInput geeft het script wat de eigenschap bevat — een tekenreeks, een getal, een
booleaanse waarde, of een object of array in zijn geheel, die een script doorloopt
per lid (f.fileName) en met length(). Een contract dat in zijn requestSchema een
gestructureerde invoer beschrijft, kan die dus ook echt lezen:
"par_document": {
"type": "object",
"additionalProperties": false,
"required": ["fileName", "contentType", "contentBase64"],
"properties": {
"fileName": { "type": "string", "maxLength": 260 },
"contentType": { "type": "string", "maxLength": 200 },
"sizeBytes": { "type": "integer" },
"contentBase64": { "type": "string", "maxLength": 5600000 }
}
}
Tot portals-ronde 10 kwam een object binnen als ruwe JSON-tekst, die BS Lang op geen enkele manier kan parsen — dus een maker die de gewenste vorm declareerde, was slechter af dan iemand die haar platsloeg tot losse eigenschappen, en dat is het tegenovergestelde van waar een schema voor dient. De nestingdiepte is begrensd door de eigen limiet van 64 niveaus van de JSON-parser, nog voordat iets hiervan wordt bereikt.
Wat het nooit doet
Een aangepaste API verruimt de toegang niet. De recordfuncties van het script gaan door dezelfde deur als de eigen schermen van het platform en draaien als de aanroeper, dus diens rechten op een tabel en het gegevensbeleid daarachter bepalen wat er terugkomt. Een zorgvuldig samengesteld contract geeft een extern systeem een stabiele blik, nooit een bredere.