Easy SharePoint ListItem CRUD Operation Using REST API Wrapper

I have read lots of articles on C# Corner, as well as on other online websites about CRUD operations on Sharepoint List. In most articles, I have found some redundant code which can be reused and utilized in such a way that any new developer or learner can learn from the code.

So, based on that, I have started working on creating SPRest Utility which will do lots of work internally to increase development speed with much less coding. As I am still working and it is not fully optimized, there is still redundant code and methods which I have to delete.
 
SPRest.js 
  1. var SPRest = /** @class */ (function () {  
  2.     function SPRest(rootWeb) {  
  3.         var _this = this;  
  4.         this.Utils = (function () {  
  5.             /** 
  6.              * Reference or motivation link : https://github.com/omkarkhair/sp-jello/blob/master/lib/jello.js 
  7.              * https://github.com/abhishekseth054/SharePoint-Rest 
  8.              * https://github.com/gunjandatta/sprest 
  9.              */  
  10.             var reqUrl = _this.rootUrl + "/_api/web/lists/getbytitle('AWSResponseList')/items";  
  11.             //var fetch = require("node-fetch");  
  12.             // TODO- Need to transform this json to closure function to allow only get operation.  
  13.             //TODO  - Need to add support for Field Meta in utils  
  14.             var spDefaultMeta = {  
  15.                 List: {  
  16.                     BaseTemplate: 100,  
  17.                     // "Title": "List Created with Fetch UTIL1112",  
  18.                     __metadata: { type: "SP.List" }  
  19.                 },  
  20.                 Document: {  
  21.                     __metadata: { type: "SP.List" },  
  22.                     AllowContentTypes: true,  
  23.                     BaseTemplate: 101,  
  24.                     ContentTypesEnabled: true  
  25.                     // 'Description': 'My doc. lib. description',  
  26.                     // 'Title': 'Test'  
  27.                 },  
  28.                 ListItem: {  
  29.                     __metadata: { type: "SP.Data.AWSResponseListListItem" }  
  30.                     // "Title": "Test"  
  31.                 }  
  32.             };  
  33.             console.log(_this.rootUrl);  
  34.             var isOdataVerbose = true;  
  35.             var _rootUrl = _this.rootUrl;  
  36.             //Here "Accept" and "Content-Type" header must require for Sharepoint Onlin REST API  
  37.             var _payloadOptions = {  
  38.                 method: "GET",  
  39.                 body: undefined,  
  40.                 headers: {  
  41.                     credentials: "include",  
  42.                     Accept: "application/json; odata=verbose",  
  43.                     "Content-Type""application/json; odata=verbose"  
  44.                 }  
  45.             };  
  46.             // TODO- To support for param base odata  
  47.             //No to fetch Metadata, response only requested data.  
  48.             // Reference link https://www.microsoft.com/en-us/microsoft-365/blog/2014/08/13/json-light-support-rest-sharepoint-api-released/  
  49.             //Option 1: verbose “accept: application/json; odata=verbose”  
  50.             //Option 2: minimalmetadata “accept: application/json; odata=minimalmetadata”  
  51.             //Option 3: nometadata “accept: application/json; odata=nometadata”  
  52.             //Option 4: Don’t provide it “accept: application/json” This defaults to minimalmetadata option  
  53.             if (!isOdataVerbose) {  
  54.                 _payloadOptions.headers.Accept = "application/json; odata=nometadata";  
  55.             }  
  56.             // Reference from :https://www.tjvantoll.com/2015/09/13/fetch-and-errors/  
  57.             //Reference rom : https://sharepoint.stackexchange.com/questions/105380/adding-new-list-item-using-rest  
  58.             // Get List Item Type metadata  
  59.             var getItemTypeForListName = function (name) {  
  60.                 return ("SP.Data." +  
  61.                     name.charAt(0).toUpperCase() +  
  62.                     name  
  63.                         .split(" ")  
  64.                         .join("")  
  65.                         .slice(1) +  
  66.                     "ListItem");  
  67.             };  
  68.             var Get = function (url) {  
  69.                 var _localPayload = _payloadOptions;  
  70.                 _localPayload.method = "GET";  
  71.                 //Internally if body is set for GET request then need to remove it by setting undefined  
  72.                 // otherwise it return with error : Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body  
  73.                 _localPayload.body = undefined;  
  74.                 delete _localPayload.headers["IF-MATCH"];  
  75.                 delete _localPayload.headers["X-HTTP-Method"];  
  76.                 console.log(_localPayload);  
  77.                 return fetch(url, _localPayload).then(function (r) { return r.json(); });  
  78.             };  
  79.             var getRequestDigest = function (url) {  
  80.                 if (url === void 0) { url = ""; }  
  81.                 if (url) {  
  82.                     url = _this.rootUrl;  
  83.                 }  
  84.                 url += "/_api/contextinfo";  
  85.                 var _localPayload = _payloadOptions;  
  86.                 _localPayload.method = "POST";  
  87.                 return fetch(url, _payloadOptions).then(function (r) { return r.json(); });  
  88.             };  
  89.             var postWithRequestDigestExtension = function (url, _a) {  
  90.                 var _b = _a.headers, headers = _b === void 0 ? {} : _b, payload = _a.payload;  
  91.                 return getRequestDigest().then(function (token) {  
  92.                     // payload.requestDigest = token.d.GetContextWebInformation.FormDigestValue;  
  93.                     headers["X-RequestDigest"] =  
  94.                         token.d.GetContextWebInformation.FormDigestValue;  
  95.                     return PostExtension(url, { headers: headers, payload: payload });  
  96.                 });  
  97.             };  
  98.             var postWithRequestDigest = function (url, payload) {  
  99.                 return getRequestDigest().then(function (token) {  
  100.                     payload.requestDigest =  
  101.                         token.d.GetContextWebInformation.FormDigestValue;  
  102.                     return Post(url, payload);  
  103.                 });  
  104.             };  
  105.             //Need to refactor below method and need to merge in single method postWithRequestDigestExtension  
  106.             //Based on Action Type in headers using switch case add or remove extra headers  
  107.             // Try to add header name same as standard name so it can be replaced with for loop e.g. _extraHeaders  
  108.             var updateWithRequestDigest = function (url, payload) {  
  109.                 return getRequestDigest(payload.rootUrl + "/_api/contextinfo").then(function (token) {  
  110.                     payload.requestDigest =  
  111.                         token.d.GetContextWebInformation.FormDigestValue;  
  112.                     payload._extraHeaders = {  
  113.                         "IF-MATCH""*",  
  114.                         "X-HTTP-Method""MERGE"  
  115.                     };  
  116.                     //For Update operation or Merge Operation no response will return only status will return for http request  
  117.                     payload.isNoJsonResponse = true;  
  118.                     return Post(url, payload);  
  119.                 });  
  120.             };  
  121.             var deleteWithRequestDigest = function (url, payload) {  
  122.                 return getRequestDigest(payload.rootUrl + "/_api/contextinfo").then(function (token) {  
  123.                     payload.requestDigest =  
  124.                         token.d.GetContextWebInformation.FormDigestValue;  
  125.                     payload._extraHeaders = {  
  126.                         "IF-MATCH""*",  
  127.                         "X-HTTP-Method""DELETE"  
  128.                     };  
  129.                     //For Update operation or Merge Operation no response will return only status will return for http request  
  130.                     payload.isNoJsonResponse = true;  
  131.                     return Post(url, payload);  
  132.                 });  
  133.             };  
  134.             var Post = function (url, payload) {  
  135.                 var _localPayload = _payloadOptions;  
  136.                 // TODO For Safety this method can be wrapped with request Digest so always get token.  
  137.                 // But need to ensure it request only when request digest is expired.  
  138.                 _localPayload.method = "POST";  
  139.                 _localPayload.body = payload.data;  
  140.                 var _metaInfo = payload.metaInfo;  
  141.                 //Pre validation Check Before update body or meta detail  
  142.                 if (_metaInfo && spDefaultMeta[_metaInfo.type]) {  
  143.                     //Update Title and Description while creating new List/Column/Fields  
  144.                     var type = _metaInfo.type, title = _metaInfo.title, listName = _metaInfo.listName;  
  145.                     var _body = spDefaultMeta[type];  
  146.                     if (title) {  
  147.                         //Update title if it is present in metaInfo  
  148.                         _body.Title = title;  
  149.                     }  
  150.                     if (type === "ListItem") {  
  151.                         //TODO Extra Efforts  
  152.                         _body.__metadata.type = getItemTypeForListName(listName);  
  153.                     }  
  154.                     //If Extra fields are present then store to payload  
  155.                     //Before Stringify ,store extra fields/columns in body  
  156.                     if (payload.extraFields) {  
  157.                         for (var field in payload.extraFields) {  
  158.                             //Add all extra columns in body  
  159.                             // TODO- Need to ensure that column value is stringify  
  160.                             _body[field] = payload.extraFields[field];  
  161.                         }  
  162.                         // Merge two object  
  163.                         // _localPayload.body = Object.assign({}, _localPayload.body, payload.extraFields)  
  164.                     }  
  165.                     //Pass body data as stringyfy;  
  166.                     _localPayload.body = JSON.stringify(_body);  
  167.                     _localPayload.body.Title = title;  
  168.                 }  
  169.                 //If Extra header is present in payload for update or other operation, Append to existing header  
  170.                 if (payload._extraHeaders) {  
  171.                     for (var _header in payload._extraHeaders) {  
  172.                         _localPayload.headers[_header] = payload._extraHeaders[_header];  
  173.                     }  
  174.                 }  
  175.                 else {  
  176.                     //IF Not present that means it is POST Request, reset Extraheader for this request  
  177.                     _localPayload.headers["IF-MATCH"] = undefined;  
  178.                     _localPayload.headers["X-HTTP-Method"] = undefined;  
  179.                 }  
  180.                 _localPayload.headers["X-RequestDigest"] = payload.requestDigest;  
  181.                 console.log(_localPayload);  
  182.                 //TODO- Naming convention can be updated.  
  183.                 if (payload.isNoJsonResponse) {  
  184.                     return fetch(url, _localPayload).then(function (r) { return r; });  
  185.                 }  
  186.                 else {  
  187.                     return fetch(url, _localPayload).then(function (r) { return r.json(); });  
  188.                 }  
  189.             };  
  190.             var PostExtension = function (url, _a) {  
  191.                 var headers = _a.headers, payload = _a.payload;  
  192.                 var _localPayload = {};  
  193.                 _localPayload = _payloadOptions;  
  194.                 // TODO For Safety this method can be wrapped with request Digest so always get token.  
  195.                 // But need to ensure it request only when request digest is expired.  
  196.                 _localPayload.method = "POST";  
  197.                 //If Extra header is present in payload for update or other operation, Append to existing header  
  198.                 if (headers) {  
  199.                     for (var _header in headers) {  
  200.                         _localPayload.headers[_header] = headers[_header];  
  201.                     }  
  202.                 }  
  203.                 //Below code not required to reset functionality  
  204.                 //    else {  
  205.                 //     //IF Not present that means it is POST Request, reset Extraheader for this request  
  206.                 //     __copyPayloadOptions.headers["IF-MATCH"] = undefined;  
  207.                 //     __copyPayloadOptions.headers["X-HTTP-Method"] = undefined;  
  208.                 //   }  
  209.                 //TODO -Assume payload is in object so applied stringyfy other wise need check before apply  
  210.                 _localPayload.body = JSON.stringify(payload.data);  
  211.                 // console.log(_payloadOptions);  
  212.                 //TODO- Naming convention can be updated.  
  213.                 // if (payload.isNoJsonResponse) {  
  214.                 //Instead of storing  extra info in payload use headers  
  215.                 if (payload.isNoJsonResponse) {  
  216.                     return fetch(url, _localPayload).then(function (r) { return r; });  
  217.                 }  
  218.                 else {  
  219.                     return fetch(url, _localPayload).then(function (r) { return r.json(); });  
  220.                 }  
  221.             };  
  222.             /** 
  223.              * Generate GUID in javascript 
  224.              * Reference from : https://github.com/andrewconnell/sp-o365-rest/blob/master/SpRestBatchSample/Scripts/App.js 
  225.              */  
  226.             function generateUUID() {  
  227.                 var d = new Date().getTime();  
  228.                 var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {  
  229.                     var r = (d + Math.random() * 16) % 16 | 0;  
  230.                     d = Math.floor(d / 16);  
  231.                     return (c == "x" ? r : (r & 0x7) | 0x8).toString(16);  
  232.                 });  
  233.                 return uuid;  
  234.             }  
  235.             /** 
  236.          * Prepare batch request in Sharepoint Online 
  237.          * Reference from : https://github.com/andrewconnell/sp-o365-rest/blob/master/SpRestBatchSample/Scripts/App.js 
  238.          */  
  239.             var GenerateBatchRequest = function (_a) {  
  240.                 var _b = _a.listName, listName = _b === void 0 ? "" : _b, data = _a.data, _c = _a.DigestValue, DigestValue = _c === void 0 ? "" : _c, _d = _a.action, action = _d === void 0 ? "ADD" : _d, _e = _a.itemIds, itemIds = _e === void 0 ? [] : _e;  
  241.                 // generate a batch boundary  
  242.                 var batchGuid = generateUUID();  
  243.                 // creating the body  
  244.                 var batchContents = new Array();  
  245.                 var changeSetId = generateUUID();  
  246.                 // get current host  
  247.                 // var temp = document.createElement('a');  
  248.                 // temp.href = this.rootUrl;  
  249.                 // var host = temp.hostname;  
  250.                 // iterate through each employee  
  251.                 ////TODO NEED TO SEPARATE BATCH OPERATION CREATION FOR ADD,UPDATE and DELETE OPERATION  
  252.                 // MIXED INSERT and UPDATE Operation  
  253.                 // MIXED ISERT ,UPDATE and DELETE Operation  
  254.                 for (var _index = 0; _index < data.length; _index++) {  
  255.                     //TODO for payload or "data"  need to generate or extract metadata based on type and batch action  
  256.                     var _item = data[_index];  
  257.                     if (action === "UPDATE") {  
  258.                         _item.Title = "##Updated_" + _item.Title;  
  259.                     }  
  260.                     //Generate and prepare request url for each item  
  261.                     switch (action) {  
  262.                         case "ADD":  
  263.                             var endpoint = generateRestRequest({ listName: listName, type: "ListItem" });  
  264.                             break;  
  265.                         case "UPDATE":  
  266.                             var endpoint = generateRestRequest({  
  267.                                 listName: listName,  
  268.                                 type: "ListItem",  
  269.                                 Id: itemIds[_index]  
  270.                             });  
  271.                             _item.Title += _index;  
  272.                             break;  
  273.                         case "DELETE":  
  274.                             var endpoint = generateRestRequest({  
  275.                                 listName: listName,  
  276.                                 type: "ListItem",  
  277.                                 Id: itemIds[_index]  
  278.                             });  
  279.                             break;  
  280.                     }  
  281.                     // create the request endpoint  
  282.                     // create the changeset  
  283.                     batchContents.push("--changeset_" + changeSetId);  
  284.                     batchContents.push("Content-Type: application/http");  
  285.                     batchContents.push("Content-Transfer-Encoding: binary");  
  286.                     batchContents.push("");  
  287.                     if (action === "UPDATE") {  
  288.                         batchContents.push("PATCH " + endpoint + " HTTP/1.1");  
  289.                         batchContents.push("If-Match: *");  
  290.                         batchContents.push("Content-Type: application/json;odata=verbose");  
  291.                         batchContents.push("");  
  292.                         batchContents.push(JSON.stringify(_item));  
  293.                     }  
  294.                     else if (action === "ADD") {  
  295.                         batchContents.push("POST " + endpoint + " HTTP/1.1");  
  296.                         batchContents.push("Content-Type: application/json;odata=verbose");  
  297.                         batchContents.push("");  
  298.                         batchContents.push(JSON.stringify(_item));  
  299.                     }  
  300.                     else if (action === "DELETE") {  
  301.                         batchContents.push("DELETE " + endpoint + " HTTP/1.1");  
  302.                         batchContents.push("If-Match: *");  
  303.                     }  
  304.                     //Commented POST request line and added code for UPDATE as well  
  305.                     // batchContents.push("POST " + endpoint + " HTTP/1.1");  
  306.                     // batchContents.push("Content-Type: application/json;odata=verbose");  
  307.                     // batchContents.push("");  
  308.                     // batchContents.push(JSON.stringify(_item));  
  309.                     batchContents.push("");  
  310.                 }  
  311.                 // END changeset to create data  
  312.                 batchContents.push("--changeset_" + changeSetId + "--");  
  313.                 // batch body  
  314.                 var batchBody = batchContents.join("\r\n");  
  315.                 batchContents = [];  
  316.                 // create batch for creating items  
  317.                 batchContents.push("--batch_" + batchGuid);  
  318.                 batchContents.push('Content-Type: multipart/mixed; boundary="changeset_' +  
  319.                     changeSetId +  
  320.                     '"');  
  321.                 batchContents.push("Content-Length: " + batchBody.length);  
  322.                 batchContents.push("Content-Transfer-Encoding: binary");  
  323.                 batchContents.push("");  
  324.                 batchContents.push(batchBody);  
  325.                 batchContents.push("");  
  326.                 // create request in batch to get all items after all are created  
  327.                 ////Commented below endpoint as we are utilizing same endpoint without orderby  
  328.                 // endpoint = _this.rootUrl +  
  329.                 //     "/_api/web/lists/getbytitle('" + listName + "')" +  
  330.                 //     '/items?$orderby=Title';  
  331.                 // batchContents.push('--batch_' + batchGuid);  
  332.                 // batchContents.push('Content-Type: application/http');  
  333.                 // batchContents.push('Content-Transfer-Encoding: binary');  
  334.                 // batchContents.push('');  
  335.                 //COmmented below lines of code as I don't need to request GET after insertion  
  336.                 // batchContents.push('GET ' + endpoint + ' HTTP/1.1');  
  337.                 // batchContents.push('Accept: application/json;odata=verbose');  
  338.                 // batchContents.push('');  
  339.                 batchContents.push("--batch_" + batchGuid + "--");  
  340.                 batchBody = batchContents.join("\r\n");  
  341.                 // create the request endpoint  
  342.                 var batchEndpoint = _this.rootUrl + "/_api/$batch";  
  343.                 // var batchRequestHeader = {  
  344.                 //     'X-RequestDigest': DigestValue,  
  345.                 //     'Content-Type': 'multipart/mixed; boundary="batch_' + batchGuid + '"'  
  346.                 // };  
  347.                 return getRequestDigest().then(function (r) {  
  348.                     //SPECIAL CASE IS BATCH REQUEST MODE  
  349.                     var batchRequestHeader = {  
  350.                         "X-RequestDigest": r.d.GetContextWebInformation.FormDigestValue,  
  351.                         "Content-Type"'multipart/mixed; boundary="batch_' + batchGuid + '"'  
  352.                     };  
  353.                     return fetch(batchEndpoint, {  
  354.                         method: "POST",  
  355.                         headers: batchRequestHeader,  
  356.                         body: batchBody  
  357.                     }).then(function (r) { return r.text(); });  
  358.                 });  
  359.                 //return PostExtension(batchEndpoint,{headers:batchRequestHeader,payload:batchBody})  
  360.                 //fetch(batchEndpoint,{method:'POST',headers:batchRequestHeader,body:batchBody}).then(r=>r.text()).then(r=>console.log(r))  
  361.                 //OLD CODE Commented  
  362.                 // create request  
  363.                 // jQuery.ajax({  
  364.                 //     url: endpoint,  
  365.                 //     type: 'POST',  
  366.                 //     headers: batchRequestHeader,  
  367.                 //     data: batchBody,  
  368.                 //     success: function(response) {  
  369.                 //         var responseInLines = response.split('\n');  
  370.                 //         //  $("#tHead").append("<tr><th>First Name</th><th>Last Name</th><th>Technology</th></tr>");  
  371.                 //         for (var currentLine = 0; currentLine < responseInLines.length; currentLine++) {  
  372.                 //             try {  
  373.                 //                 var tryParseJson = JSON.parse(responseInLines[currentLine]);  
  374.                 //                 console.log(tryParseJson);  
  375.                 //             } catch (e) {  
  376.                 //                 console.log("Error")  
  377.                 //             }  
  378.                 //         }  
  379.                 //     },  
  380.                 //     fail: function(error) {  
  381.                 //     }  
  382.                 // });  
  383.             };  
  384.             var generateRestRequest = function (_a) {  
  385.                 var _b = _a.listName, listName = _b === void 0 ? "" : _b, _c = _a.Id, Id = _c === void 0 ? "" : _c, type = _a.type, _d = _a.oDataOption, oDataOption = _d === void 0 ? "" : _d, _e = _a.url, url = _e === void 0 ? "" : _e;  
  386.                 if (url) {  
  387.                     return url;  
  388.                 }  
  389.                 var prepareRequest = _this.rootUrl + "/_api/web/lists";  
  390.                 switch (type) {  
  391.                     case "ListItem":  
  392.                         prepareRequest += "/getbytitle('" + listName + "')/items";  
  393.                         if (Id) {  
  394.                             prepareRequest += "(" + Id + ")";  
  395.                         }  
  396.                         if (oDataOption) {  
  397.                             prepareRequest += "?" + oDataOption;  
  398.                         }  
  399.                         break;  
  400.                     case "List":  
  401.                         if (listName) {  
  402.                             prepareRequest += "/getbytitle('" + listName + "')";  
  403.                         }  
  404.                         if (oDataOption) {  
  405.                             prepareRequest += "?" + oDataOption;  
  406.                         }  
  407.                         //TODO  
  408.                         break;  
  409.                     case "MSGraph":  
  410.                         //Special Case  
  411.                          
  412.                         break;  
  413.                 }  
  414.                 //OLDER Code for ListItem  
  415.                 //   prepareRequest = `/getbytitle('${listName}')/items`;  
  416.                 //   if (Id) {  
  417.                 //     prepareRequest += `(${Id})`;  
  418.                 //   }  
  419.                 return prepareRequest;  
  420.             };  
  421.             //Provide support for odata query so, for specific provided expression append it with base requet  
  422.             var ListItem = {  
  423.                 Add: function (_a) { },  
  424.                 Update: function (_a) { },  
  425.                 Delete: function (_a) { },  
  426.                 GetItemById: function (_a) { },  
  427.                 GetAllItem: function (_a) { }  
  428.             };  
  429.             var List = {  
  430.                 Add: function (_a) { },  
  431.                 Update: function (_a) {  
  432.                     console.log("Implementation is pending");  
  433.                 },  
  434.                 Delete: function (_a) {  
  435.                     console.log("Implementation is pending");  
  436.                 },  
  437.                 GetByTitle: function (_a) {  
  438.                     console.log("Implementation is pending");  
  439.                 },  
  440.                 GetAll: function (_a) { }  
  441.             };  
  442.             List.GetAll = function (_a) {  
  443.                 var _b = _a.oDataOption, oDataOption = _b === void 0 ? "" : _b, _c = _a.url, url = _c === void 0 ? "" : _c;  
  444.                 return Get(generateRestRequest({ listName: "", type: "List", oDataOption: oDataOption, url: url }));  
  445.             };  
  446.             List.GetByTitle = function (_a) {  
  447.                 var listName = _a.listName, oDataOption = _a.oDataOption, url = _a.url;  
  448.                 return Get(generateRestRequest({ listName: listName, type: "List", oDataOption: oDataOption, url: url }));  
  449.             };  
  450.             List.Add = function (_a) {  
  451.                 var listName = _a.listName, data = _a.data;  
  452.                 var _reqUrl = generateRestRequest({ listName: listName, type: "List" });  
  453.                 var _prePayload = preparePayloadData({  
  454.                     action: "ADD",  
  455.                     type: "List",  
  456.                     listName: listName,  
  457.                     data: data  
  458.                 });  
  459.                 return postWithRequestDigestExtension(_reqUrl, _prePayload);  
  460.             };  
  461.             ListItem.GetAllItem = function (_a) {  
  462.                 var listName = _a.listName, _b = _a.oDataOption, oDataOption = _b === void 0 ? "" : _b, _c = _a.url, url = _c === void 0 ? "" : _c;  
  463.                 return Get(generateRestRequest({ listName: listName, type: "ListItem", oDataOption: oDataOption, url: url }));  
  464.             };  
  465.             ListItem.GetItemById = function (_a) {  
  466.                 var listName = _a.listName, Id = _a.Id, _b = _a.oDataOption, oDataOption = _b === void 0 ? "" : _b, _c = _a.url, url = _c === void 0 ? "" : _c;  
  467.                 return Get(generateRestRequest({ listName: listName, Id: Id, type: "ListItem", oDataOption: oDataOption, url: url }));  
  468.             };  
  469.             // Add/Update/Delete require same types of metaData as well as payload only difference is Headers  
  470.             ListItem.Add = function (_a) {  
  471.                 var listName = _a.listName, data = _a.data;  
  472.                 var _reqUrl = generateRestRequest({ listName: listName, type: "ListItem" });  
  473.                 var _prePayload = preparePayloadData({  
  474.                     action: "ADD",  
  475.                     type: "ListItem",  
  476.                     listName: listName,  
  477.                     data: data  
  478.                 });  
  479.                 return postWithRequestDigestExtension(_reqUrl, _prePayload);  
  480.             };  
  481.             ListItem.Update = function (_a) {  
  482.                 var listName = _a.listName, Id = _a.Id, data = _a.data;  
  483.                 var _reqUrl = generateRestRequest({ listName: listName, Id: Id, type: "ListItem" });  
  484.                 var _prePayload = preparePayloadData({  
  485.                     action: "UPDATE",  
  486.                     type: "ListItem",  
  487.                     listName: listName,  
  488.                     data: data  
  489.                 });  
  490.                 return postWithRequestDigestExtension(_reqUrl, _prePayload);  
  491.             };  
  492.             ListItem.Delete = function (_a) {  
  493.                 var listName = _a.listName, Id = _a.Id, data = _a.data;  
  494.                 var _reqUrl = generateRestRequest({ listName: listName, Id: Id, type: "ListItem" });  
  495.                 var _prePayload = preparePayloadData({  
  496.                     action: "DELETE",  
  497.                     type: "ListItem",  
  498.                     listName: listName,  
  499.                     data: data  
  500.                 });  
  501.                 return postWithRequestDigestExtension(_reqUrl, _prePayload);  
  502.             };  
  503.             var preparePayloadData = function (_a) {  
  504.                 var listName = _a.listName, data = _a.data, action = _a.action, type = _a.type;  
  505.                 var payload = {  
  506.                     data: { __metadata: spDefaultMeta[type] }  
  507.                 };  
  508.                 //payload.data = {};  
  509.                 //   let _metaInfo: any = spDefaultMeta["ListItem"];  
  510.                 //   _metaInfo.__metadata.type = getItemTypeForListName(listName);  
  511.                 // payload.data.__metadata=spDefaultMeta["ListItem"];  
  512.                 switch (type) {  
  513.                     case "ListItem":  
  514.                         //Update ListItem Content type  
  515.                         payload.data.__metadata.type = getItemTypeForListName(listName);  
  516.                         break;  
  517.                 }  
  518.                 //Need to check is data is object then iterate otherwise not  
  519.                 if (data) {  
  520.                     for (var _key in data) {  
  521.                         payload.data[_key] = data[_key];  
  522.                     }  
  523.                 }  
  524.                 //TODO Verify about extra header  
  525.                 // //Pass body data as stringyfy;  
  526.                 // // _payloadOptions.body = JSON.stringify(_body);  
  527.                 // // _payloadOptions.body.Title = title;  
  528.                 //    return postWithRequestDigest(_reqUrl);  
  529.                 var _headers = {};  
  530.                 switch (action) {  
  531.                     case "ADD":  
  532.                         _headers = {  
  533.                             "IF-MATCH": undefined,  
  534.                             "X-HTTP-Method": undefined  
  535.                         };  
  536.                         break;  
  537.                     case "UPDATE":  
  538.                         _headers = {  
  539.                             "IF-MATCH""*",  
  540.                             "X-HTTP-Method""MERGE"  
  541.                         };  
  542.                         //For Update operation or Merge Operation no response will return only status will return for http request  
  543.                         payload.isNoJsonResponse = true;  
  544.                         break;  
  545.                     case "DELETE":  
  546.                         _headers = {  
  547.                             "IF-MATCH""*",  
  548.                             "X-HTTP-Method""DELETE"  
  549.                         };  
  550.                         //For Update operation or Merge Operation no response will return only status will return for http request  
  551.                         payload.isNoJsonResponse = true;  
  552.                         break;  
  553.                 }  
  554.                 return { headers: _headers, payload: payload };  
  555.             };  
  556.             return {  
  557.                 ListItem: ListItem,  
  558.                 Get: Get,  
  559.                 getRequestDigest: getRequestDigest,  
  560.                 Post: postWithRequestDigest,  
  561.                 Update: updateWithRequestDigest,  
  562.                 Delete: deleteWithRequestDigest,  
  563.                 BatchInsert: GenerateBatchRequest  
  564.             };  
  565.         })();  
  566.         this.rootUrl = rootWeb;  
  567.     }  
  568.     return SPRest;  
  569. }());   
You might be wondering how to use SPRest for CRUD Operation in SharePoint.
 
First of all, save the above code in a file and then, add the reference to it on the page wherever you want to use it.
 
If you want to use this SPRest utility in your SPFx web part or add it using TypeScript, then you can find compatible SpRest.ts at my repo.
 
Once you have added references, then create the instance of SPRest with one parameter which accepts Sharepoint rootUrl used internally or generating request URL for REST API.
  1. var spRest=new SPRest("https://brgrp.sharepoint.com")  
For demonstration purposes, I am using "PlaceHolderList" that is having the following columns.
  • Title -Single line of Text
  • UserId - Number
  • Completed -Single line of Text

Get All List Items from Sharepoint List

 
By default, SharePoint List returns the top 100 records if you have more than 100 records in the list.
  1. // Get All Item from List item  
  2. spRest.Utils.ListItem.GetAllItem({listName:"PlaceHolderList"}).then(function(r){  
  3. console.log(r);  
  4. // Response received. TODO bind record to table or somewhere else.  
  5. });  

Get All List Items from Sharepoint List using URL or with  oDataOption

 
Get Selected columns using $select and use $top in oDataOptions from the list or you can use full URL which will directly pass to get data based on the option in URL.
 
Here you can request list item with your selected column and filter in URL, you can use all supported odata option in URL to get full 
response,
Or 
you can just pass list name other oDataOption as shown below without adding a question mark at starting to get same data and if you required next paginated response you can just pass "__next" in url.
  1. //Get all selected column Data using full URL  
  2. util.Utils.ListItem  
  3. .GetAllItem({  
  4.    url:"https://brgrp.sharepoint.com/_api/web/lists/getbytitle('PlaceHolderList')/items?$select=Id,Title&$top=200"  
  5. }).then(function(r){console.log(r);  
  6. //Response Received  
  7. });  
  8.   
  9. //Get all selected column data with listName and oDataOption  
  10.   
  11. util.Utils.ListItem.GetAllItem(  
  12.    {"listName":"PlaceHolderList"  
  13.       ,oDataOption:"$select=Id,Title&$top=200"  
  14.    }).then(function(r){console.log(r);  
  15.    //Response Received  
  16. });  

Note
Here if you have passed both listname and url then query will be executed based on only url, listName and oDataOption value not considered.

Get List Item from SharePoint List by Id
  1. // Get List Item By Id  
  2. spRest.Utils.ListItem.GetItemById({listName:"PlaceHolderList",Id:201}).then(function(r){    
  3. console.log(r);    
  4. // Response received.   
  5. });   

Add New List Item to SharePoint List

  1. // Add ListItem to Sharepoint List  
  2. spRest.Utils.ListItem.Add({listName:"PlaceHolderList",data:{Title:"New Item Created For Demo",UserId:1,Completed:"true"}}).then(function(r){    
  3. console.log(r);    
  4. // Added New List item response received with newly created item  
  5. });   

Update New List Item By Id in SharePoint List

  1. // Update List item based on ID with new data in SharePoint List  
  2. spRest.Utils.ListItem.Update({listName:"PlaceHolderList",Id:201,data:{Title:"Updated List Item",UserId:1,Completed:"true"}}).then(function(r){    
  3. // List Item Updated and received response with status 204  
  4. console.log(r);  
  5. });   

Delete New List Item By Id in SharePoint List

  1. // Delete List item based on ID  
  2. spRest.Utils.ListItem.Delete({listName:"PlaceHolderList",Id:201}).then(function(r){    
  3. // List Item Deleted and received response with status 200  
  4. console.log(r);  
  5. });   
As per the above code example for CRUD functionality, it looks like a cleaner and easier way to perform the CRUD opeation on SharePoint List. It has a lot of redundant code.
  • Generate Request Url Based on Root Site and List Name and Id
  • Header accept and Content type
  • RequestDigest Headers
  • Combined Delete/Update/Add  Code with reusable functions to prepare payload data for the request
  • Adding and applying metadata for ListItem based on ListName
I removed and combined with reusable functions so it can be used for extending List and Document Library in the future.
 
I hope you find this article and utilities helpful. Let me know your comments and any suggestion to extend SPRest util.
 
All implementation and source code for SPRest can be found on GitHub.
 
Change History:
 
18-Apr-2018: Updated SPRest.js  to support oDataOption and direct URL as a parameter in util function to get the paginated item.

Conclusion

 
In this article, we have learned about an easy and cleaner way to do CRUD Operations with SharePoint List Items using SPRest.