Spring til indholdet

Opret listeelementer med REST fra Power Automate

Endpoints, headers og body til at oprette og rette elementer med Send an HTTP request to SharePoint, feltformat for hver felttype og de fejl, SharePoint svarer med.

Opdateret Power AutomateSharePoint Online 7 min. læsning

Create item klarer tekst, tal, datoer og valg. Når et felt ikke vil — managed metadata, flere personer, flere opslag — eller når jeg vil have fejlen i hånden i stedet for et rødt kryds, opretter jeg elementet med Send an HTTP request to SharePoint mod REST-API’et. Handlingen hører til SharePoint-connectoren og kræver ikke Premium. Det gør den generiske HTTP-handling.

Hyperlinkfelter og personfelter med StringId står for sig i Link- og personfelter på et listeelement med HTTP i Power Automate. Her er resten.

Endpoints#

POST https://[site]/_api/web/lists/getbytitle('[ListName]')/items
POST https://[site]/_api/web/lists/getbytitle('[ListName]')/items([ItemID])
GET https://[site]/_api/web/lists/getbytitle('[ListName]')/items([ItemID])

Den første opretter, den anden retter (med en X-HTTP-Method), den tredje henter.

Headers#

Opret:

1{
2  "Accept": "application/json;odata=verbose",
3  "Content-Type": "application/json;odata=verbose"
4}

Ret de felter, der står i body (MERGE):

1{
2  "Accept": "application/json;odata=verbose",
3  "Content-Type": "application/json;odata=verbose",
4  "X-HTTP-Method": "MERGE",
5  "IF-MATCH": "*"
6}

Erstat hele elementet (PUT):

1{
2  "Accept": "application/json;odata=verbose",
3  "Content-Type": "application/json;odata=verbose",
4  "X-HTTP-Method": "PUT",
5  "IF-MATCH": "*"
6}

X-HTTP-Method laver en POST om til MERGE, PUT eller DELETE. IF-MATCH: * betyder, at versionen er ligegyldig. Med en ETag i stedet for * afviser SharePoint ændringen, hvis nogen har rettet elementet imellemtiden.

Body#

Mindst:

1{
2  "__metadata": {
3    "type": "SP.Data.[ListName]ListItem"
4  },
5  "Title": "Item Title"
6}

Med flere felter:

 1{
 2  "__metadata": {
 3    "type": "SP.Data.TasksListItem"
 4  },
 5  "Title": "Complete Documentation",
 6  "AssignedToId": 42,
 7  "DueDate": "2025-04-30",
 8  "Status": "In Progress",
 9  "Priority": "High"
10}

Fremgangsmåde#

1. Hent listens typenavn. Det skal stå i __metadata.type, og det er ikke altid det, listens navn får én til at gætte.

Site Address: [Your SharePoint site]
Method: GET
Uri: _api/web/lists/getbytitle('[ListName]')?$select=ListItemEntityTypeFullName
Headers:
{
  "Accept": "application/json;odata=verbose"
}
1{
2  "d": {
3    "ListItemEntityTypeFullName": "SP.Data.TasksListItem"
4  }
5}
Initialize variable - varMetadataType
Value: body('Get_List_Metadata')?['d']?['ListItemEntityTypeFullName']

2. Læg værdierne i variabler. Så er body til at læse, og tomme værdier kan fanges, før kaldet laves.

varTitle: "Q1 2025 Review"
varAssignedToId: 42
varDueDate: "2025-03-31"
varStatus: "New"
varPriority: "High"
varDescription: "Quarterly review of all projects"

3. Opret elementet.

Site Address: [Your SharePoint site]
Method: POST
Uri: _api/web/lists/getbytitle('Tasks')/items
Headers:
{
  "Accept": "application/json;odata=verbose",
  "Content-Type": "application/json;odata=verbose"
}
Body:
{
  "__metadata": {
    "type": "@{variables('varMetadataType')}"
  },
  "Title": "@{variables('varTitle')}",
  "AssignedToId": @{variables('varAssignedToId')},
  "DueDate": "@{variables('varDueDate')}",
  "Status": "@{variables('varStatus')}",
  "Priority": "@{variables('varPriority')}",
  "Description": "@{variables('varDescription')}"
}

Tekst og datoer står i anførselstegn, tal og ja/nej gør ikke. Datoer skrives ISO 8601: "2025-03-31".

4. Læs svaret (valgfrit). Et oprettet element giver status 201 og elementet tilbage.

Content: body('Create_Item_HTTP')
Schema:
{
  "type": "object",
  "properties": {
    "d": {
      "type": "object",
      "properties": {
        "Id": { "type": "integer" },
        "Title": { "type": "string" },
        "Created": { "type": "string" },
        "Author": {
          "type": "object",
          "properties": {
            "Title": { "type": "string" }
          }
        }
      }
    }
  }
}
Item ID: body('Parse_JSON')?['d']?['Id']
Created Date: body('Parse_JSON')?['d']?['Created']
Author: body('Parse_JSON')?['d']?['Author']?['Title']

Felttyper#

Feltnavnet er altid det interne navn.

Tekst. En linje, flere linjer og rich text:

1"Title": "Project Alpha"
1"Description": "This is a detailed description\nwith line breaks"
1"RichDescription": "<div><strong>Bold text</strong> and <em>italic</em></div>"

Tal. Heltal, decimaltal, procent og valuta. Procent gemmes som en brøk: 0.75 er 75 %.

1"Quantity": 100
1"Price": 99.95
1"CompletionRate": 0.75
1"Budget": 50000.00

Dato og tid. Kun dato, dato med tid, og nu:

1"DueDate": "2025-03-31"
1"MeetingDateTime": "2025-03-31T14:30:00Z"
1"ProcessedDate": "@{utcNow()}"

Valg. Ét valg er bare teksten. Flere valg er en samling:

1"Status": "In Progress"
1"Categories": {
2  "__metadata": { "type": "Collection(Edm.String)" },
3  "results": ["High Priority", "Customer Facing"]
4}

Ja/nej:

1"IsActive": true,
2"IsArchived": false

Person. Feltnavnet får Id på, og værdien er brugerens id på webstedet. Én person:

1"AssignedToId": 42

eller

1"AssignedToStringId": "42"

Flere personer:

1"TeamMembersId": {
2  "__metadata": { "type": "Collection(Edm.Int32)" },
3  "results": [42, 57, 89]
4}

Id’et findes med ensureuser (se fejl 5 herunder), som også lægger brugeren på webstedet, hvis vedkommende ikke er der. Get user profile (V2) giver Entra-objekt-id’et, og det er ikke det samme tal.

Opslag. Samme mønster: feltnavn plus Id, og værdien er id’et på elementet i opslagslisten.

1"ProjectId": 15
1"RelatedProjectsId": {
2  "__metadata": { "type": "Collection(Edm.Int32)" },
3  "results": [15, 23, 47]
4}

Hyperlink:

1"Website": {
2  "__metadata": { "type": "SP.FieldUrlValue" },
3  "Description": "Company Website",
4  "Url": "https://example.com"
5}

Beregnede felter kan ikke sættes. SharePoint regner dem selv ud.

Managed metadata. WssId er -1 for et term, der ikke er brugt på webstedet før:

1"DepartmentId": {
2  "__metadata": { "type": "SP.Taxonomy.TaxonomyFieldValue" },
3  "Label": "IT Department",
4  "TermGuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
5  "WssId": -1
6}

Ikke efterprøvet: flere kilder sætter objektet på feltets interne navn uden Id ("Department": {...}). Virker den ene ikke, er det den anden.

Fejlhåndtering#

To mønstre. Et try/catch med to scopes:

Scope: Try Create Item
  Send HTTP request - Create item
  Parse JSON response

Scope: Catch Error
  Configure run after (on Try scope): has failed, has timed out
  
  Compose - Error Details:
    body('Create_item')?['error']?['message']
  
  Send email - Notify admin
  
  Create item - Log error to audit list

Eller en betingelse på statuskoden:

Send HTTP request - Create item

Condition: Status code equals 201 (Created)

If yes:
  Parse response
  Continue workflow
  
If no:
  Log error
  Send notification
  Terminate flow

Betingelsen kræver, at HTTP-handlingen ikke stopper flowet ved fejl, altså Configure run after på det næste trin.

Fejl, SharePoint svarer med#

“The property ‘FieldName’ does not exist”. Forkert internt navn. Slå det op:

GET _api/web/lists/getbytitle('ListName')/fields?$filter=Title eq 'Display Name'

Navnet skelner mellem store og små bogstaver, og mellemrum står som _x0020_.

“Invalid JSON format”. Et komma for meget eller for lidt, et anførselstegn der ikke er lukket, eller et specialtegn i en variabel. Det hjælper at bygge body i en Compose først og se, hvad der faktisk bliver sendt.

“A value without a type name was found”. __metadata mangler eller har den forkerte type:

1{
2  "__metadata": {
3    "type": "SP.Data.TasksListItem"
4  }
5}

“The request ETag value does not match”. Elementet er ændret siden sidst. IF-MATCH: * ser bort fra det:

1Headers:
2{
3  "IF-MATCH": "*"
4}

“User cannot be found”. Brugeren er ikke på webstedet endnu. ensureuser lægger vedkommende der og giver id’et tilbage:

POST _api/web/ensureuser
Body: { "logonName": "user@domain.com" }

Mange elementer på én gang#

Flere oprettelser kan sendes i ét kald til $batch. Eksemplet her viser formen:

POST _api/$batch
Content-Type: multipart/mixed; boundary=batch_xxxxxxxx

--batch_xxxxxxxx
Content-Type: application/http
Content-Transfer-Encoding: binary

POST _api/web/lists/getbytitle('Tasks')/items
{"__metadata":{"type":"SP.Data.TasksListItem"},"Title":"Item 1"}

--batch_xxxxxxxx
Content-Type: application/http

POST _api/web/lists/getbytitle('Tasks')/items
{"__metadata":{"type":"SP.Data.TasksListItem"},"Title":"Item 2"}

--batch_xxxxxxxx--

Som det står, går det ikke igennem. Skriveoperationer skal ligge i et changeset, der er sin egen multipart/mixed-del med sin egen boundary inde i batchen, og hver indre forespørgsel skal have sine egne Content-Type- og Accept-headers og en tom linje før body. Alle adresser i batchen skal pege på samme websted. Et changeset er ikke en transaktion: fejler én oprettelse, bliver de andre stående. Microsofts eksempler står under Make batch requests with the REST APIs.

Mønstre#

Felter ud fra regler. En Switch på prioriteten sætter frist og ansvarlig, før elementet oprettes:

Switch: triggerOutputs()?['body/Priority']

Case "High":
  Set varDueDate: addDays(utcNow(), 1)
  Set varAssignedTo: variables('varManagerId')
  
Case "Medium":
  Set varDueDate: addDays(utcNow(), 7)
  Set varAssignedTo: variables('varTeamLeadId')
  
Case "Low":
  Set varDueDate: addDays(utcNow(), 30)
  Set varAssignedTo: variables('varTeamMemberId')

Create item via HTTP with conditional values

Skabeloner. JSON i et tekstfelt i en liste, hentet efter elementtype, parset og brugt som udgangspunkt for body.

1. Store templates in SharePoint list (JSON in text field)
2. Get template based on item type
3. Parse template JSON
4. Populate variables from template
5. Create item via HTTP

Rul tilbage. Fejler noget efter oprettelsen, slettes elementet igen:

Scope: Try
  Create item via HTTP
  Parse response - Store Item ID
  Perform additional operations
  
Scope: Catch
  Configure run after: has failed
  
  Condition: Item was created
    variables('varItemId') is not null
  
  If yes:
    DELETE _api/web/lists/getbytitle('Tasks')/items(@{variables('varItemId')})

DELETE sendes som POST med X-HTTP-Method: DELETE og IF-MATCH: *.

Prøv igen med stigende pause:

Do Until: Success or MaxRetries
  
  Try create item
  
  If fails:
    Increment retry count
    Delay: 2^retryCount seconds
    Continue loop
  
  If succeeds:
    Break loop

HTTP-handlingen har også sin egen Retry policy under indstillingerne, som klarer 429 og 5xx uden en løkke.

Det der driller#

  • Typenavnet følger listens oprindelige navn, ikke det nuværende. En liste, der er omdøbt, beholder sit gamle SP.Data.…ListItem. Derfor henter jeg det i stedet for at gætte.
  • Interne navne er ikke visningsnavne. Et felt oprettet som “Due Date” hedder Due_x0020_Date, også efter det er omdøbt.
  • Personer og opslag vil have tal, ikke navne eller e-mails. Id’et på en person er webstedets id, ikke Entra-id’et.
  • Sprog. Interne navne er de samme på et dansk og et engelsk websted, visningsnavne er ikke. Datoer sendes som yyyy-MM-dd, aldrig som 31-03-2025. formatDateTime(variables('varDueDate'), 'yyyy-MM-dd') ordner det.

Alle noter