When it comes to content management, how would you deal with automating it?

You’ve probably thought of Data Exchange Framework for setting up content import from external sources on a regular basis, or Sitecore PowerShell Extensions as the universal Swiss Army knife that allows doing everything.

Sitecore XM Cloud is a modern SaaS solution and therefore offers you one more way of managing and importing content via GraphQL mutations. This is also an option for the latest 10.3 XM/XP platforms bringing them a step closer to the composable world of today.

Please welcome: Authoring and Management API!

The documentation prompts a broad and awe-inspiring list of things you can do with Authoring API against your instance: create and delete items, templates, and media. It also empowers you to do some operations around site context and perform a content search on your CM instance.

Management API in addition gives you control over operations using queries and mutations for the following GraphQL types:

Archiving
Database
Indexing
Job
Language
Publishing
Security
Workflow
Rules

With that in mind, you can create and structure your content, reindex, and publish it to Experience Edge entirely using this API. So let’s take a look at how it works!

Uploading a picture to Media Library using GraphQL Authoring API

First of all, it is disabled by default, so we need to switch by setting Sitecore_GraphQL_ExposePlayground environmental variable to true. Since these variables expand at build time you also need to re-deploy the environments

Once deployment is complete, you can start playing with it. Security in a composable world typically works with OAuth, Authoring and Management API is not an exclusion here. In order to obtain an access token, you need to authorize it first with your client ID and client secret which you set up with XM Cloud Deploy app:

There are different ways of authorization (for example, using CLI dotnet sitecore cloud login command), but since the need to fully automate the routine, I will be using /oauth/token endpoint. Also, it is worth mentioning that after getting initially already authorized with CLI, your client ID / secret pair is stored at .sitecoreuser.json file so let’s take it from there. Here’s the code:

$userJson = “$PSScriptRoot/../../.sitecore/user.json”

if (-not (Test-Path $userJson)) {
Write-Error “The specified file ‘$userJson’ does not exist.”
return
}

$userJson = Get-Content $userJson | ConvertFrom-Json

$clientId = $userJson.endpoints.xmCloud.clientId
$clientSecret = $userJson.endpoints.xmCloud.clientSecret
$authorityUrl = $userJson.endpoints.xmCloud.authority
$audience = $userJson.endpoints.xmCloud.audience
$grantType = “client_credentials”

$body = @{
client_id = $clientId
client_secret = $clientSecret
audience = $audience
grant_type = $grantType
}

$response = Invoke-RestMethod -Uri “${authorityUrl}oauth/token” -Method Post -ContentType “application/x-www-form-urlencoded” -Body $body
return $response.access_token

Now we got the access token and it should be passed as a header with every single request to GraphQL API:

“Authorization” = “Bearer <access_token>”

Next, let’s make a mutation query that returns us a pre-signed upload URL from passing API endpoint and a target Sitecore path that you want to upload your media to. Here’s the code:

[CmdletBinding()]
Param (
[Parameter(Mandatory=$true, HelpMessage=”The URL of the endpoint where the file will be uploaded.”)]
[string]$EndpointUrl,
[Parameter(Mandatory=$true, HelpMessage=”The JWT token to use for authentication.”)]
[string]$JWT,
[Parameter(Mandatory=$true, HelpMessage=”The path of the file to be uploaded.”)]
[string]$UploadPath
)

$query = @”
mutation
{
uploadMedia(input: { itemPath: “$UploadPath” }) {
presignedUploadUrl
}
}
“@

$body = @{ query = $query} | ConvertTo-Json
$headers = @{
“Content-Type” = “application/json”
“Authorization” = “Bearer $JWT”
}

# Invoke the GraphQL endpoint using Invoke-RestMethod and pass in the query and headers
$response = Invoke-RestMethod -Method POST -Uri $EndpointUrl -Headers $headers -Body $body
$result = $response.data.uploadMedia
return $result.presignedUploadUrl

Now having the pre-signed upload URL, we can perform media upload passing the local file to process:

[CmdletBinding()]
Param (
[Parameter(Mandatory=$true, HelpMessage=”The URL to upload the file to.”)]
[string]$UploadUrl,
[Parameter(Mandatory=$true, HelpMessage=”The JWT token to use for authentication.”)]
[string]$JWT,
[Parameter(Mandatory=$true, HelpMessage=”The path to the file to be uploaded.”)]
[string]$FilePath
)

if (-not (Test-Path $FilePath)) {
Write-Error “The specified file ‘$FilePath’ does not exist.”
return
}

$result = & curl.exe –request POST $UploadUrl –header “Authorization: Bearer $JWT” –form =@”$FilePath” -s
$result = $result | ConvertFrom-Json
return $result

This script will return the details of a newly uploaded media item, such as:

item name
item full path
item ID

I combined all the above cmdlets into a single Demo-UploadPicture.ps1 script that cares about passing all the parameters and performs the upload operation:

The upload immediately results in Media Library at the requested path:

Pros:

a modern platform agnostic approach
works nicely with webhooks
allows automating pretty much everything
excellent management options making DevOps easier

Cons:

cumbersome token operations
doesn’t allow batching, therefore takes a request per each operation

Verdict

It is great to have a variety of different tools in your belt rather than having a single hammer in a hand with everything around turning into nails. Hope this new tool brings your automation skills to a new level!