Compartilhar via


Introdução à API Web do Microsoft Dynamics 365 (Javascript no cliente)

 

Publicado: janeiro de 2017

Aplicável a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Em recursos da Web HTML, scripts de formulários, ou comandos da faixa de opções que você pode usar JavaScript para realizar operações nos dados Microsoft Dynamics 365 usando o Web API apresentado com Microsoft Dynamics 365 (online e local).

O Web API é especialmente fácil de usar com JavaScript e recursos da Web porque os dados do JSON enviados e recebidos com, é facilmente convertido em objetos JavaScript. No entanto, a maioria dos desenvolvedores desejarão criar ou usar uma biblioteca JavaScript auxiliar para tirar proveito da reutilização de código e manter o código da lógica comercial separado do código para acessar os dados. Este tópico mostra como usar o objeto XMLHttpRequest para executar operações com JavaScript assim como para criar bibliotecas reutilizáveis JavaScript que forneçam funções para trabalhar com o Web API.

Neste tópico

Áreas onde você pode usar o JavaScript no cliente

Entendendo o XMLHttpRequest

Usando o XMLHttpRequest

Criando dados de JSON para enviar

Análise JSON retornada

Criar uma função reutilizável usando retornos de chamada

Criar uma função reutilizável usando retornos de promessas

Áreas onde você pode usar o JavaScript no cliente

Há duas áreas onde você pode usar JavaScript do cliente para acessar Microsoft Dynamics 365 usando a API da Web:

  • Recursos da Web JavaScript
    Código JavaScript incluído em um recurso da Web JavaScript executando no contexto de um recurso da Web HTML, scripts de formulário ou comandos da faixa de opções.

    Quando você usa recursos da Web JavaScript em Microsoft Dynamics 365 você não precisa se autenticar porque os recursos da Web são parte do aplicativo que o usuário ainda será autenticado. O restante deste tópico sobre centrar-se-á esse cenário.Para obter mais informações:Recursos da Web do Microsoft Dynamics 365,Recursos da Web de script (JScript), Usar o Javascript com o Microsoft Dynamics 365 e Bibliotecas JavaScript para Microsoft Dynamics 365.

  • Escolha aplicativos da página
    Código JavaScript em uma biblioteca JavaScript de outro aplicativo em execução em um navegador e fazendo a autenticação no Microsoft Dynamics 365 usando o Compartilhamento de Recursos entre Origens (CORS). O padrão é tipicamente usado para aplicativos da página opções.

    Quando você usa JavaScript em um único aplicativo na página (SPA) você pode usar a biblioteca de adal.js para permitir que autentica o usuário acesse dados e Microsoft Dynamics 365 em uma página hospedado em um domínio diferente. A maioria das informações deste tópico aplicam-se a este cenário mas você também deve integrar cabeçalho de autorização em qualquer solicitação que contenha um token de autenticação. Para obter mais informações, consulte Use o OAuth com compartilhamento de recursos entre origens para conectar um aplicativo de página única ao Microsoft Dynamics 365

Entendendo o XMLHttpRequest

Quando você usa a Web API usará um objeto XMLHttpRequest.XMLHttpRequest (XHR) é um objeto nativo localizado nos navegadores modernos, e habilita técnicas AJAX para tornar as páginas da Web dinâmicas. Embora o nome de objeto contém "XML", todas as solicitações usando o API da Web usarão JSON em vez do XML.

Estrutura utilizada por XMLHttpRequest Javascript

As estruturas de JavaScript como jQuery geralmente envolvem o objeto subjacente XMLHttpRequest em uma função (como $.ajax) porque previamente nem todos os navegadores fornecem um XMLHttpRequest nativo d uma forma padrão e também fácil de usar. Agora que navegadores modernos têm uma implementação XMLHttpRequest padrão, não será preciso uma biblioteca separada para atenuar as diferenças. Embora muitos desenvolvedores continuem a depender das estruturas JavaScript para solicitar recursos do servidor. Como é fácil usar o jQuery e outras estruturas JavaScript nos recursos da Web ou SPAs, HTML, recomendamos evitá-los em scripts ou faixas de opções de comandos no formulário. Com diversas soluções que podem ser instaladas em uma organização, cada uma inclui potencialmente diferentes versões de uma estrutura JavaScript, especialmente jQuery, pode levar a resultados inesperados a não ser que todos realizem etapas para evitar conflitos. Se você executará solicitações da API da Web em scripts ou faixa de opções de comandos, é recomendável usar o XMLHttpRequest diretamente para você e não em uma dependência de jQuery.Para obter mais informações:Uso do jQuery

Este tópico mostra como usar o XMLHttpRequest nativo diretamente, mas os mesmos conceitos serão aplicados ao usar jQuery ou outras estruturas JavaScript executadas em um navegador desde que todos usem XMLHttpRequest. Você pode usar uma biblioteca que use XHR diretamente em um navegador com qualquer estrutura JavaScript.

Usando o XMLHttpRequest

O exemplo a seguir é muito simples e mostram como criar uma entidade de conta usando a API da Web e o objeto XMLHttpRequest. Neste exemplo, somente a variável clientURL não é definida.

var req = new XMLHttpRequest()
req.open("POST",encodeURI(clientURL + "/api/data/v8.1/accounts"), true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
 if (this.readyState == 4 /* complete */) {
  req.onreadystatechange = null;
  if (this.status == 204) {
   var accountUri = this.getResponseHeader("OData-EntityId");
   console.log("Created account with URI: "+ accountUri)
  }
  else {
   var error = JSON.parse(this.response).error;
   console.log(error.message);
  }
 }
};
req.send(JSON.stringify({ name: "Sample account" }));

As seções a seguir descrevem o que este código faz.

Abra o XMLHttpRequest

Após inicializar o objeto XMLHttpRequest, você precisará abri-lo para poder definir as propriedades ou enviá-las. Os parâmetros de método open estão em um método de solicitação HTTP, um URL e um parâmetro boolean para indicar se a operação deve ser realizada de forma assíncrona. Você deve sempre optar por executar operações de maneira assíncrona.Para obter mais informações:Use métodos assíncronos de acesso a dados

Neste exemplo, como estamos criando uma entidade de conta, precisamos definir a URL para o caminho da entidade de account EntityType. O completo URL neste exemplo é clientURL + "/api/data/v8.1/accounts e a variável clientURL deve ser definida para URL raiz do aplicativo Microsoft Dynamics 365. Para recursos da Web que têm acesso ao objeto de contexto, a função getClientUrl que pode ser acessada por meio de objeto de contexto do cliente disponível usando o Função GetGlobalContext em um recurso da Web HTML ou o objeto Xrm.Page.context em um script de formulário ou comando da faixa de opções. Você deve usar a função encodeURI em qualquer URL enviado ao serviço para garantir que ele não contém caracteres não seguros.

Como esta função cria uma entidade, o método de solicitação HTTP é POST como descrito em Criar uma entidade usando a API da Web.

O método XMLHttpRequestopen também fornece a um usuário específico um nome e senha. Não é preciso especificar um valor para os parâmetros com recursos Web pois o usuário já está autenticado. Para termas, a autenticação é gerenciada por meio de um token em vez dos parâmetros.

Definir os títulos e o manipulador de eventos

Depois que você abrir o XMLHttpRequest você pode aplicar um número de solicitações de cabeçalho usando o método setRequestHeader. Você deve usar os títulos exibidos com algumas variações aqui para tipos especiais de operações.Para obter mais informações:Cabeçalhos HTTP.

Antes de enviar a solicitação, você precisa incluir um manipulador de evento que detecta a conclusão da operação. Após o envio da solicitação, avance por meio de vários estágios antes da resposta ser retornada. Para capturar o momento que o XMLHttpRequest é concluído, você deve definir um manipulador de evento para lidar com a propriedade onreadystatechange para detectar quando a propriedade readystate for igual a 4, que indica conclusão. Neste momento você pode verificar a propriedade status.

Observação

Após o XMLHttpRequest ser concluído, é uma prática boa definir a propriedade onreadystatechange para null para evitar problemas de vazamento de memória em potencial.

Dentro da função anônima que é o manipulador de eventos, após a conclusão ser verificada, você poderá examinar a propriedade status para determinar se o processo foi bem-sucedido. Nesse caso, o valor de status esperado é 204 No Content porque nada é esperado no corpo da resposta da operação de criação. A URI para a conta criada no cabeçalho OData-EntityId pode ser acessada usando o método getResponseHeader.

Se esta for uma operação diferente que deve retornar os dados em resposta, ela teria um valor 200 OKstatus e a função usaria JSON.parse na resposta XMLHttpRequest para converter a resposta JSON em um objeto JavaScript que seu código conseguiria acessar.Para obter mais informações:Análise JSON retornada

Se o status não for esperado, o valor é um erro e o objeto de erro será retornado pelas propriedades descritas em Erros parciais da resposta. Este exemplo usa JSON.parse para converter o objeto XMLHttpRequestresponse property into a JavaScript para que a propriedade message possa ser acessada.

Enviar o XMLHttpRequest

Por fim, use o método XMLHttpRequestsend para enviar a solicitação, incluindo todos os dados JSON necessários. Use JSON.stringify para converter os objetos JavaScript a segmentos JSON que podem ser incluídos no corpo das solicitações ao enviar.

Criando dados de JSON para enviar

No exemplo acima, a entidade de conta é criada com apenas um único conjunto da propriedade. Para determinar quais propriedades estão disponíveis para uma entidade, você precisa olhar para Documento CSDL dos metadadosda documentação gerada de um documento, ou de código gerado com o documento. Para entidades empresariais do sistema incluídas em todas as organizações Microsoft Dynamics 365 você pode consultar o Web API EntityType Reference. Os nomes de propriedade estão em minúscula e aceitam os tipos de dados simples que correspondem aos seguintes tipos JavaScript: Boolean, Number, String, Array, Object e Date.

Observação

A única exceção a usar tipos de dados simples BooleanManagedProperty ComplexType é usado para as entidades que armazenam dados solução- cientes como recursos da Web, modelos, relatórios, funções, savedqueries, e em entidades de metadados. Esta propriedade é usada para nunca as entidades que armazenam dados corporativos. As entidades usam muitos tipos de metadados complexos e acompanhar regras diferentes. Para obter mais informações, consulte Use o API da Web com metadados do Dynamics 365.

Criar dados para enviar uma solicitação normalmente é uma simples questão de um objeto JavaScript comum é definir propriedades apropriadas. O código a seguir mostra dois métodos válidos para definir um objeto JavaScript com propriedades e valores. Esse exemplo usa as propriedades selecionadas de entidade de contato definidas em contact EntityType.

var contact = new Object();
contact.firstname = "John";
contact.lastname = "Smith";
contact.accountrolecode = 2; //Employee
contact.creditonhold = false; //Number value works here too. 0 is false and 1 is true
contact.birthdate = new Date(1980, 11, 2);
contact["parentcustomerid_account@odata.bind"] = "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"

var contact = {
 firstname: "John",
 lastname: "Smith",
 accountrolecode: 2,//Employee
 creditonhold: false,
 birthdate: new Date(1980, 11, 2),
 "parentcustomerid_account@odata.bind": "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"
};

Independentemente de como esses objetos são definidos, depois de usar JSON.stringify ambos serão convertidos na mesma cadeia de caracteres JSON.

    {
     "firstname": "John",
     "lastname": "Smith",
     "accountrolecode": 2,
     "creditonhold": false,
     "birthdate": "1980-12-02T08:00:00.000Z",
     "parentcustomerid_account@odata.bind": "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"
    }

Existem situações em que você deve definir a propriedade que não acompanha a propriedade de nome comum de diretrizes para JavaScript. Por exemplo, quando você define o valor de uma propriedade única avaliada na navegação ao criar uma entidade que você precisa para acrescentar @odata.bind ao nome da propriedade e definir o valor de uma URL que corresponde à entidade relacionada. Nesse caso, é necessário definir a propriedade em um estilo de anotação em parênteses como mostrado no exemplo acima.

Ao trabalhar com entidades exceto os metadados, não defina propriedades de entidade para um objeto. Com entidades de metadados é necessário definir a frequência das propriedades que são valores de tipo ou complexo de enumeração. Mas isso não é comum com comerciais de entidades.

Ao criar entidades relacionadas você pode definir o valor de coleção de uma propriedade usando Array avaliado na navegação, mas essa é uma operação especializada.Para obter mais informações:Criar entidades relacionadas em uma operação

Propriedades de tipo de entidade

Quando você posta uma entidade em uma ação no tipo de parâmetro que representa um tipo de base da entidade, como crmbaseentity EntityType or activitypointer EntityType, você pode precisar incluir a propriedade @odata.type com o nome completo do tipo da entidade assim como o valor. Por exemplo, como letter EntityType herda do activitypointer, talvez seja necessário indicar o tipo de entidade usando as seguintes propriedades e valor:"@odata.type": "Microsoft.Dynamics.CRM.letter".

Enviar dados de operações de atualização

Quando você atualiza as entidades, é importante definir valores de propriedade de apenas as propriedades que você pretende atualizar. Você não pode recuperar uma entidade, propriedades da atualização da instância recuperadas e usar essa operação em uma instância de atualização. Em vez disso, você deve criar um novo conjunto de objeto e as propriedades somente novas para as propriedades que você pretende atualizar.

Se copiar somente as propriedades de uma entidade recuperadas e atualizar as que usam PATCH, cada uma das propriedades que você envia uma atualização será considerada, se o valor for o mesmo do valor atual. Se você tiver a auditoria habilitada para a entidade e o atributo ela indicará que os dados são modificados quando não houver uma alteração do valor real.Para obter mais informações:Atualização básica

Análise JSON retornada

Embora a operação de criação usada no exemplo acima não devolva dados JSON, a maioria das operações usando GET retornará JSON. Para a maioria dos tipos de dados retornados, converter o JSON em JavaScript pode sempre ser o objetivo da seguinte linha de código.

var data = JSON.parse(this.response)

Entretanto, os dados que incluem datas são um problema pois as datas são transmitidas como uma cadeia de caracteres, por exemplo 2015-10-25T17:23:55Z. Para convertê-lo em um objeto JavaScriptDate você deve usar o parâmetro reviver para a função JSON.parse. O diagrama a seguir é um exemplo de uma função que pode ser usada para análise parcial de datas.

function dateReviver(key, value) {
  var a;
  if (typeof value === 'string') {
   a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
   if (a) {
    return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
   }
  }
  return value;
 };

Para aplicar essa função inclua-a como um parâmetro, como ilustrado a seguir.

var data = JSON.parse(this.response,dateReviver)

Criar uma função reutilizável usando retornos de chamada

Quando você tiver um código para executar uma operação específica você poderá reutilizar o mesmo escrevendo o código repetidas vezes. A próxima etapa é criar uma biblioteca JavaScript que contém uma função para executar a operação com as opções disponíveis. Nesse caso há somente duas variáveis de criação da operação: o nome da entidade e JSON a definição da entidade criada. Em vez de gravar qualquer código anteriormente, conforme mostrado, na mesma operação podem estar contidas em uma função que leva apenas as linhas de código usadas.

As operações assíncronas a JavaScript tradicionalmente empregaram funções de chamada como uma maneira de capturar todos os valores da operação assíncrona para continuar a lógica na agenda. Usando o código da operação de criação descrita anteriormente, o objetivo é o mesmo da operação usando apenas a execução do código a seguir.

MyNameSpace.WebAPI.create("accounts",
{ name: "Sample account" },
function (accountUri) { console.log("Created account with URI: " + accountUri) },
function (error) { console.log(error.message); });

Neste exemplo, MyNameSpace.WebAPI representa uma prática recomendável para fornecer um nome exclusivo para quaisquer direitos que você deseja usar.Para obter mais informações:Definir nomes exclusivos para as funções de JavaScript

Nessa biblioteca planejamos para incluir mais funções de operações adicionais e uma oportunidade de que as funções atendam as operações reutilizáveis particulares. O código a seguir mostra uma biblioteca das quais esse inclui uma função MyNameSpace.WebAPI.create usando retornos de chamada.

"use strict";
var MyNameSpace = window.MyNameSpace || {};
MyNameSpace.WebAPI = MyNameSpace.WebAPI || {};
(function () {
 this.create = function (entitySetName, entity, successCallback, errorCallback) {
  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.setRequestHeader("OData-MaxVersion", "4.0");
  req.setRequestHeader("OData-Version", "4.0");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204) {
     if (successCallback)
      successCallback(this.getResponseHeader("OData-EntityId"));
    }
    else {
     if (errorCallback)
      errorCallback(MyNameSpace.WebAPI.errorHandler(this.response));
    }
   }
  };
  req.send(JSON.stringify(entity));
 };

 //Internal supporting functions
 function getClientUrl() {
  //Get the organization URL
  if (typeof GetGlobalContext == "function" &&
      typeof GetGlobalContext().getClientUrl == "function") {
   return GetGlobalContext().getClientUrl();
  }
  else {
   //If GetGlobalContext is not defined check for Xrm.Page.context;
   if (typeof Xrm != "undefined" &&
       typeof Xrm.Page != "undefined" &&
       typeof Xrm.Page.context != "undefined" &&
       typeof Xrm.Page.context.getClientUrl == "function") {
    try {
     return Xrm.Page.context.getClientUrl();
    } catch (e) {
     throw new Error("Xrm.Page.context.getClientUrl is not available.");
    }
   }
   else { throw new Error("Context is not available."); }
  }
 }
 function getWebAPIPath() {
  return getClientUrl() + "/api/data/v8.1/";
 }

 // This function is called when an error callback parses the JSON response
 // It is a public function because the error callback occurs within the onreadystatechange 
 // event handler and an internal function would not be in scope.
 this.errorHandler = function (resp) {
  try {
   return JSON.parse(resp).error;
  } catch (e) {
   return new Error("Unexpected Error")
  }
 }

}).call(MyNameSpace.WebAPI);

Essa biblioteca demonstra as práticas recomendadas para definir uma função dentro de uma função anônima de autoexecução (também conhecida como uma função autoinvocada ou função anônima invocada imediatamente) e anexar a função ao namespace MyNameSpace.WebAPI. Isso permite que você defina as funções internas que não são acessíveis por outro código. Qualquer direito que esteja definido como parte de this será público e os direitos da função anônima podem ser usados por funções públicas, mas não externas pelo código da função anônima. O código da função não pode ser modificado pelo código na página.

A namespace é definida de forma que não substitua nenhum outro símbolo que use a mesma namespace, mas substituirá as funções com o mesmo nome que sejam parte da namespace. Você pode criar as bibliotecas de preços adicionais para adicionar direitos públicos namespace que não possuem o mesmo nome.

A função MyNameSpace.WebAPI.create fornece os seguintes parâmetros:

Nome

Descrição

entitySetName

O nome da entidade definido como o tipo de entidade que deseja criar.

entity

Um objeto com as propriedades da entidade que deseja criar.

successCallback

A função para chamada quando a entidade é criada. O Uri da entidade criada é passado para essa função.

errorCallback

A função para chamada quando houver um erro. O erro será passado a esta função.

Código que configura o objeto XMLHttpRequest foi alterado para usar esses valores de parâmetro e também a função getWebAPIPath interna adicional que localizará a URI base da organização e acrescentarão a URL para que o URI raiz da API de auxiliares de modo que você não precisa inclui-lo. O URI para a entidade criada será passado para successCallback se ele for definido. De forma semelhante, a função errorHandler pública é usada para apresentaram qualquer mensagem de erro para você. A função errorHandler deve ser pública pois é chamada dentro do manipulador do evento onreadystatechange e não para escopo de namespace. Deve ser denominada com o nome completo: MyNameSpace.WebAPI.errorHandler.

Criar uma função reutilizável usando retornos de promessas

Quando os retornos de chamada tradicionalmente são usados para sensação de operações assíncronas, muitos desenvolvedores podem se sentir incomodados e com dificuldade de ler a depuração como uma série de operações assíncronas, que compilará no uso para criar código de forma da "pirâmide de destino" como o recuo do código, usando funções anônimas, para mover mais e exibir à direita da página. Embora esse problema possa ser gerado usando funções abordadas em vez de funções anônimas, muitos desenvolvedores aproveitam os benefícios oferecidos por promessas. Um objeto Promise representa uma operação que não está concluída ainda, mas se espera concluir no futuro.

Há várias bibliotecas de terceiros e estruturas de JavaScript que oferecem diferentes implementações de promessas.JQuery ofereceu um comportamento com base em CommonJS Promises/A projetado via Objeto adiado e outros persistem na união com a especificação Promessas/A+. Uma explicação das diferenças entre essas implementações além do alcance deste tópico. O objetivo desta seção é como chamar apenas uma função de Microsoft Dynamics 365 para auxiliar a API usando um objeto nativo XMLHttpRequest que pode ser criado para usar o modo Objeto de promessa nativo que são implementados na maioria dos navegadores com suporte modernos Microsoft Dynamics 365. Os seguintes navegadores têm uma solução de promessas de implementação: Google Chrome 32, Opera 19, Mozilla Firefox 29 Apple Safari 8 e Microsoft Edge.

Observação

O Internet Explorer 11 não implementa promessas nativas. Para navegadores que não prometem implementações nativas, você deve incluir uma biblioteca separada para fornecer um polyfill. Um código que é polyfill oferece os recursos não nativamente fornecidos pelo navegador. Os vários polyfills ou bibliotecas que permitirão Internet Explorer 11 ter promessas: es6-promise, q.js e bluebird.

A vantagem de usar melhor promessas pode ser demonstrada por um exemplo. O seguinte código na versão do retorno de chamada MyNameSpace.WebAPI.create para criar uma conta e em três tarefas associadas a ela.

MyNameSpace.WebAPI.create("accounts",
 { name: "Sample account" },
 function (accountUri) {
  console.log("Created account with URI: " + accountUri);
  MyNameSpace.WebAPI.create("tasks",
   { subject: "Task 1", "regardingobjectid_account_task@odata.bind": accountUri },
   function () {
    MyNameSpace.WebAPI.create("tasks",
     { subject: "Task 2", "regardingobjectid_account_task@odata.bind": accountUri },
     function () {
      MyNameSpace.WebAPI.create("tasks",
       { subject: "Task 3", "regardingobjectid_account_task@odata.bind": accountUri },
       function () {
        //Finished creating three tasks
        console.log("Three tasks created");
       },
      function (error) { console.log(error.message); });
     },
     function (error) { console.log(error.message); });
   },
  function (error) { console.log(error.message); });
 },
function (error) { console.log(error.message); });

A finalidade de ignorar este exemplo, o fato de que todos esses registros podem ser criados em uma única operação usando a inserção profunda.Para obter mais informações:Criar entidades relacionadas em uma operação

Código da devolução é chamada de término como o desafio do código. Enquanto isso, usando promessas é possível criar os mesmos registros com o código a seguir.

var accountUri;
MyNameSpace.WebAPI.create("accounts", { name: "Sample account" })
.then(function (aUri) {
 accountUri = aUri;
 console.log("Created account with URI: " + accountUri);
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 1", "regardingobjectid_account_task@odata.bind": accountUri });
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 2", "regardingobjectid_account_task@odata.bind": accountUri });
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 3", "regardingobjectid_account_task@odata.bind": accountUri });
})
.catch(function (error) { console.log(error.message); });

Usar promessas preserva o fluxo de código e permite capturar todos os erros que ocorrem em uma única função de captura.

Converter a função com retornos de chamada para usar promessas é uma questão de remover as definições de retorno de chamada e de XMLHttpRequest, retornar levemente alterado, conforme mostrado no seguinte código de exemplo.

return new Promise(function (resolve, reject) {
 var req = new XMLHttpRequest();
 req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
 req.setRequestHeader("Accept", "application/json");
 req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
 req.setRequestHeader("OData-MaxVersion", "4.0");
 req.setRequestHeader("OData-Version", "4.0");
 req.onreadystatechange = function () {
 if (this.readyState == 4 /* complete */) {
  req.onreadystatechange = null;
  if (this.status == 204) {
  resolve(req.getResponseHeader("OData-EntityId"));
  }
  else {
  reject(MyNameSpace.WebAPI.errorHandler(req.response));
  }
 }
 };
 req.send(JSON.stringify(entity));
});

Além de mover os parâmetros de chamada, o XMLHttpRequest é incluído do Promise e em vez de transmitir erros ou resultados dos retornos de sucesso ou chamadas de erro eles passaram para o parâmetro resolve ou reject. O código a seguir representa a biblioteca JavaScript inteira que contém a função MyNameSpace.WebAPI.create. Tudo que for deixado para fazer é adicionar mais reutilizáveis de operações Web API com o mesmo padrão.

"use strict";
var MyNameSpace = window.MyNameSpace || {};
MyNameSpace.WebAPI = MyNameSpace.WebAPI || {};
(function () {
 /** @description Create a new entity
  * @param {string} entitySetName The name of the entity set for the type of entity you want to create.
  * @param {object} entity An object with the properties for the entity you want to create.
  */
 this.create = function (entitySetName, entity) {
  /// <summary>Create a new entity</summary>
  /// <param name="entitySetName" type="String">The name of the entity set for the entity you want to create.</param>
  /// <param name="entity" type="Object">An object with the properties for the entity you want to create.</param>       
  if (!isString(entitySetName)) {
   throw new Error("MyNameSpace.WebAPI.create entitySetName parameter must be a string.");
  }
  if (isNullOrUndefined(entity)) {
   throw new Error("MyNameSpace.WebAPI.create entity parameter must not be null or undefined.");
  }

  return new Promise(function (resolve, reject) {
   var req = new XMLHttpRequest();
   req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
   req.setRequestHeader("Accept", "application/json");
   req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
   req.setRequestHeader("OData-MaxVersion", "4.0");
   req.setRequestHeader("OData-Version", "4.0");
   req.onreadystatechange = function () {
    if (this.readyState == 4 /* complete */) {
     req.onreadystatechange = null;
     if (this.status == 204) {
      resolve(req.getResponseHeader("OData-EntityId"));
     }
     else {
      reject(MyNameSpace.WebAPI.errorHandler(req.response));
     }
    }
   };
   req.send(JSON.stringify(entity));
  });

 };

 //Internal supporting functions
 function getClientUrl() {
  //Get the organization URL
  if (typeof GetGlobalContext == "function" &&
      typeof GetGlobalContext().getClientUrl == "function") {
   return GetGlobalContext().getClientUrl();
  }
  else {
   //If GetGlobalContext is not defined check for Xrm.Page.context;
   if (typeof Xrm != "undefined" &&
       typeof Xrm.Page != "undefined" &&
       typeof Xrm.Page.context != "undefined" &&
       typeof Xrm.Page.context.getClientUrl == "function") {
    try {
     return Xrm.Page.context.getClientUrl();
    } catch (e) {
     throw new Error("Xrm.Page.context.getClientUrl is not available.");
    }
   }
   else { throw new Error("Context is not available."); }
  }
 }
 function getWebAPIPath() {
  return getClientUrl() + "/api/data/v8.1/";
 }

 //Internal validation functions
 function isString(obj) {
  if (typeof obj === "string") {
   return true;
  }
  return false;

 }
 function isNull(obj) {
  if (obj === null)
  { return true; }
  return false;
 }
 function isUndefined(obj) {
  if (typeof obj === "undefined") {
   return true;
  }
  return false;
 }
 function isFunction(obj) {
  if (typeof obj === "function") {
   return true;
  }
  return false;
 }
 function isNullOrUndefined(obj) {
  if (isNull(obj) || isUndefined(obj)) {
   return true;
  }
  return false;
 }
 function isFunctionOrNull(obj) {
  if (isNull(obj))
  { return true; }
  if (isFunction(obj))
  { return true; }
  return false;
 }

 // This function is called when an error callback parses the JSON response.
 // It is a public function because the error callback occurs in the onreadystatechange 
 // event handler and an internal function wouldn’t be in scope.
 this.errorHandler = function (resp) {
  try {
   return JSON.parse(resp).error;
  } catch (e) {
   return new Error("Unexpected Error")
  }
 }

}).call(MyNameSpace.WebAPI);

Confira Também

Use a API da Web do Microsoft Dynamics 365
Trabalhar com dados de Dynamics 365 usando recursos da Web
Executar operações usando A API
Exemplos de API da Web (JavaScript do cliente)
Use o OAuth com compartilhamento de recursos entre origens para conectar um aplicativo de página única ao Microsoft Dynamics 365

Microsoft Dynamics 365

© 2017 Microsoft. Todos os direitos reservados. Direitos autorais