One Microsoft 365 person can arrive in three different shapes depending on whether the data came from SharePoint REST, Microsoft Graph, or an older custom endpoint. If that inconsistency leaks into the front end, every template fills up with “if Graph, do this; if REST, do that.”
The problem: the same email has three paths
// SharePoint REST
$row['Employee_x0020_Email']
// Microsoft Graph list item
$row['fields']['EmployeeEmail']
// Custom API
$row['emailAddress']
Names are worse. A source may provide Title, displayName, or separate first and last names. URL fields may be a string in Graph but an object containing Url and Description in SharePoint.
The quirk: null, empty, and missing are different
If one source returns null, another omits the property, and a third returns “N/A,” the consumer becomes harder to test. I normalize immediately.
function normalizePerson(array $row, string $source): array
{
$f = $source === 'graph' ? ($row['fields'] ?? []) : $row;
$url = $f['ProfileUrl'] ?? '';
if (is_array($url)) {
$url = $url['Url'] ?? '';
}
return [
'bannerId' => trim($f['BannerID'] ?? ''),
'name' => trim($f['DisplayName'] ?? $f['Title'] ?? ''),
'email' => strtolower(trim($f['EmployeeEmail'] ?? $f['emailAddress'] ?? '')),
'url' => trim($url)
];
}
The workaround: normalize once, then forget the source
After this function runs, downstream code only understands bannerId, name, email, and url. Moving from REST to Graph becomes an adapter change instead of a site-wide rewrite.
