Tutorial: Use portal Web API
Note
Effective October 12, 2022, Power Apps portals is Power Pages. More information: Microsoft Power Pages is now generally available (blog)
We will soon migrate and merge the Power Apps portals documentation with Power Pages documentation.
In this tutorial, you'll set up a webpage and custom web template that will use the Web API to read, write, update, and delete records from the contact table.
Note
You can change the column names, or use a different table, while following the steps in this example.
Step 1. Create site settings
Before you can use the portals Web API, you have to enable the required site settings with the Portal Management app. The site settings depend on the table that you want to use when interacting with the Web API.
Go to Power Apps.
On the left pane, select Apps.
Select the Portal Management app.
On the left pane of the Portal Management app, select Site Settings.
Select New.
In the Name box, enter Webapi/contact/enabled.
In the Website list, select your website record.
In the Value box, enter true.
Select Save & Close.
Select New.
In the Name box, enter Webapi/contact/fields.
In the Website list, select your website record.
In the Value box, enter
firstname,lastname,fullname,emailaddress1,telephone1Select Save & Close.
Select New.
In the Name box, enter Webapi/error/innererror.
In the Website list, select your website record.
In the Value box, enter true.
Select Save & Close.
Verify the site settings for Web API.
Step 2. Configure permissions
You'll have to configure permissions so that users are able to use the Web API feature. In this example, you'll enable the Contact table for table permissions, create a web role using the Web API, add the table permissions for the Contact table to this web role, and then add the web role to users in order to allow them to use the Web API.
On the left pane of the Portal Management app, select Table Permissions.
Select New.
In the Name box, enter Contact Table Permission.
In the Table Name list, select Contact (contact).
In the Website list, select your website record.
In the Access Type list, select Global.
Select Read, Write, Create, and Delete privileges.
Select Save & Close.
Create a web role
You can use an existing web role in your website or create a new web role.
On the left pane, select Web Roles .
Select New.
In the Name box, enter Web API User (or any name that best reflects the role of the user accessing this functionality).
In the Website list, select your website record.
Select Save.
Add related table permissions
With the new or existing web role, select Related > Table Permissions.
Select Add Existing Table Permission.
Select Contact Table Permission, created earlier.
Select Add.
Select Save & Close.
Add contacts to the web role
On the left pane, select Contacts.
Select a contact that you want to use in this example for the Web API.
Note
This contact is the user account used in this example for testing the Web API. Be sure to select the correct contact in your portal.
Select Related > Web Roles.
Select Add Existing Web Role.
Select the Web API User role, created earlier.
Select Add.
Select Save & Close.
Step 3. Create a webpage
Now that you've enabled the Web API and configured user permissions, create a webpage with sample code to view, edit, create, and delete records.
On the left pane of the Portal Management app, select Web Pages.
Select New.
In the Name box, enter webapi.
In the Website list, select your website record.
For Parent Page, select Home.
For Partial URL, enter webapi.
For Page Template, select Home.
For Publishing State, select Published.
Select Save.
Select Related > Web Pages.
From Web Page Associated View, select webapi.
Scroll down to the Content section, and then go to Copy (HTML) (HTML designer).
Select the HTML tab.
Copy the following sample code snippet and paste it in the HTML designer.
<!-- Sample code for Web API demonstration --> <style> #processingMsg { width: 150px; text-align: center; padding: 6px 10px; z-index: 9999; top: 0; left: 40%; position: fixed; -webkit-border-radius: 0 0 2px 2px; border-radius: 0 0 2px 2px; -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); display: none; } table td[data-attribute] .glyphicon-pencil { margin-left: 5px; opacity: 0; } table td[data-attribute]:hover .glyphicon-pencil { opacity: 0.7; } </style> <script> $(function() { //Web API ajax wrapper (function(webapi, $) { function safeAjax(ajaxOptions) { var deferredAjax = $.Deferred(); shell.getTokenDeferred().done(function(token) { // Add headers for ajax if (!ajaxOptions.headers) { $.extend(ajaxOptions, { headers: { "__RequestVerificationToken": token } }); } else { ajaxOptions.headers["__RequestVerificationToken"] = token; } $.ajax(ajaxOptions) .done(function(data, textStatus, jqXHR) { validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve); }).fail(deferredAjax.reject); //ajax }).fail(function() { deferredAjax.rejectWith(this, arguments); // On token failure pass the token ajax and args }); return deferredAjax.promise(); } webapi.safeAjax = safeAjax; })(window.webapi = window.webapi || {}, jQuery) // Notification component var notificationMsg = (function() { var $processingMsgEl = $('#processingMsg'), _msg = 'Processing...', _stack = 0, _endTimeout; return { show: function(msg) { $processingMsgEl.text(msg || _msg); if (_stack === 0) { clearTimeout(_endTimeout); $processingMsgEl.show(); } _stack++; }, hide: function() { _stack--; if (_stack <= 0) { _stack = 0; clearTimeout(_endTimeout); _endTimeout = setTimeout(function() { $processingMsgEl.hide(); }, 500); } } } })(); // Inline editable table component var webAPIExampleTable = (function() { var trTpl = '<% _.forEach(data, function(data){ %>' + '<tr data-id="<%=data.id%>" data-name="<%=data.fullname%>">' + '<% _.forEach(columns, function(col){ %>' + '<td data-attribute="<%=col.name%>" data-label="<%=col.label%>" data-value="<%=data[col.name]%>">' + '<%-data[col.name]%><i class="glyphicon glyphicon-pencil"></i>' + '</td>' + '<% }) %>' + '<td>' + '<button class="btn btn-default delete" type="submit"><i class="glyphicon glyphicon-trash" aria-hidden="true"></i></button>' + '</td>' + '</tr>' + '<% }) %>'; var tableTpl = '<table class="table table-hover">' + '<thead>' + '<tr>' + '<% _.forEach(columns, function(col){ %>' + '<th><%=col.label%></th>' + '<% }) %>' + '<th>' + '<button class="btn btn-default add" type="submit">' + '<i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add Sample Record' + '</button>' + '</th>' + '</tr>' + '</thead>' + '<tbody>' + trTpl + '</tbody>' + '</table>'; function getDataObject(rowEl) { var $rowEl = $(rowEl), attrObj = { id: $rowEl.attr('data-id'), name: $rowEl.attr('data-name') }; $rowEl.find('td').each(function(i, el) { var $el = $(el), key = $el.attr('data-attribute'); if (key) { attrObj[key] = $el.attr('data-value'); } }) return attrObj; } function bindRowEvents(tr, config) { var $row = $(tr), $deleteButton = $row.find('button.delete'), dataObj = getDataObject($row); $.each(config.columns, function(i, col) { var $el = $row.find('td[data-attribute="' + col.name + '"]'); $el.on('click', $.proxy(col.handler, $el, col, dataObj)); }); //User can delete record using this button $deleteButton.on('click', $.proxy(config.deleteHandler, $row, dataObj)); } function bindTableEvents($table, config) { $table.find('tbody tr').each(function(i, tr) { bindRowEvents(tr, config); }); $table.find('thead button.add').on('click', $.proxy(config.addHandler, $table)); } return function(config) { var me = this, columns = config.columns, addHandler = config.addHandler, deleteHandler = config.deleteHandler, $table; me.render = function(el) { $table = $(el).html(_.template(tableTpl)({ columns: columns, data: me.data })).find('table'); bindTableEvents($table, { columns: columns, addHandler: addHandler, deleteHandler: deleteHandler }); } me.addRecord = function(record) { $table.find('tbody tr:first').before(_.template(trTpl)({ columns: columns, data: [record] })); bindRowEvents($table.find('tbody tr:first'), config); } me.updateRecord = function(attributeName, newValue, record) { $table.find('tr[data-id="' + record.id + '"] td[data-attribute="' + attributeName + '"]').text(newValue); } me.removeRecord = function(record) { $table.find('tr[data-id="' + record.id + '"]').fadeTo("slow", 0.7, function() { $(this).remove(); }); } }; })(); //Applicaton ajax wrapper function appAjax(processingMsg, ajaxOptions) { notificationMsg.show(processingMsg); return webapi.safeAjax(ajaxOptions) .fail(function(response) { if (response.responseJSON) { alert("Error: " + response.responseJSON.error.message) } else { alert("Error: Web API is not available... ") } }).always(notificationMsg.hide); } function loadRecords() { return appAjax('Loading...', { type: "GET", url: "/_api/contacts?$select=fullname,firstname,lastname,emailaddress1,telephone1", contentType: "application/json" }); } function addSampleRecord() { //Sample data to create a record - change as appropriate var recordObj = { firstname: "Willie", lastname: "Huff" + _.random(100, 999), emailaddress1: "Willie.Huff@contoso.com", telephone1: "555-123-4567" }; appAjax('Adding...', { type: "POST", url: "/_api/contacts", contentType: "application/json", data: JSON.stringify(recordObj), success: function(res, status, xhr) { recordObj.id = xhr.getResponseHeader("entityid"); recordObj.fullname = recordObj.firstname + " " + recordObj.lastname; table.addRecord(recordObj); } }); return false; } function deleteRecord(recordObj) { var response = confirm("Are you sure, you want to delete \"" + recordObj.name + "\" ?"); if (response == true) { appAjax('Deleting...', { type: "DELETE", url: "/_api/contacts(" + recordObj.id + ")", contentType: "application/json", success: function(res) { table.removeRecord(recordObj); } }); } return false; } function updateRecordAttribute(col, recordObj) { var attributeName = col.name, value = recordObj[attributeName], newValue = prompt("Please enter \"" + col.label + "\"", value); if (newValue != null && newValue !== value) { appAjax('Updating...', { type: "PUT", url: "/_api/contacts(" + recordObj.id + ")/" + attributeName, contentType: "application/json", data: JSON.stringify({ "value": newValue }), success: function(res) { table.updateRecord(attributeName, newValue, recordObj); } }); } return false; } var table = new webAPIExampleTable({ columns: [{ name: 'firstname', label: 'First Name', handler: updateRecordAttribute }, { name: 'lastname', label: 'Last Name', handler: updateRecordAttribute }, { name: 'emailaddress1', label: 'Email', handler: updateRecordAttribute }, { name: 'telephone1', label: 'Telephone', handler: updateRecordAttribute }], data: [], addHandler: addSampleRecord, deleteHandler: deleteRecord }); loadRecords().done(function(data) { table.data = _.map(data.value, function(record){ record.id = record.contactid; return record; }); table.render($('#dataTable')); }); }); </script> <div id="processingMsg" class="alert alert-warning" role="alert"></div> <div id="dataTable"></div>
Select Save & Close.
Step 4. Clear the portals cache
You've created a webapi sample page to test the Web API functionality. Before you get started, ensure that the Power Apps portals cache has been cleared so that the changes from the Portal Management app are reflected on your portal.
IMPORTANT: Clearing the portal server-side cache causes temporary performance degradation of the portal while data gets reloaded from Microsoft Dataverse.
To clear the cache:
Sign in to your portal as a member of the Administrators web role.
Change the URL by appending /_services/about at the end. For example, if the portal URL is https://contoso.powerappsportals.com, change it to https://contoso.powerappsportals.com/_services/about.
NOTE: You must be a member of the Administrators web role to clear the cache. If you see a blank screen, check the web role assignments.
Select Clear cache.
More information: Clear the server-side cache for a portal
Step 5. Use the Web API to read, view, edit, create, and delete
The sample webpage with the URL webapi created earlier is now ready for testing.
To test the Web API functionality:
Sign in to your portal with the user account that has been assigned the Web API User role you created earlier.
Go to the webapi webpage created earlier. For example, https://contoso.powerappsportals.com/webapi. The WebAPI will retrieve records from Micrsoft Dataverse.
Select Add Sample Record to add the sample record from the script.
Select a field. In this example, we've selected Email to change the email address of a contact.
Select
to delete a record.
Now that you've created a webpage with a sample to read, edit, create, and delete records, you can customize the forms and layout.
Next step
Compose HTTP requests and handle errors
See also
Portals Web API overview Portals write, update and delete operations using the Web API Portals read operations using the Web API Configure column permissions
Feedback
Submit and view feedback for