Creating pages on sharepoint site with microsoft graph - sharepoint

Currently I'm trying to create a page on a newly created site with some dummy data. According to https://learn.microsoft.com/en-us/graph/api/sitepage-create?view=graph-rest-beta it should be possible to create a page using json like this:
POST https://graph.microsoft.com/beta/sites/tenant.sharepoint.com%2Cee2667f8-2bae-460e-944b-613773baaa03%2C8c0054a6-6e0e-49cd-be6d-4c4c0aaf644e/pages HTTP/1.1
Authorization: Bearer <token>
User-Agent: Java-Client
Accept-Encoding: gzip,deflate
Accept: application/json, text/json
Content-Type: application/json; charset=UTF-8
Host: graph.microsoft.com
Connection: keep-alive
Content-Length: 167
{"name":"Testpage21.aspx","publishingState":{"level":"published","versionId":"0.1"},"title":"Testpage21","webParts":[{"type":"rte","innerHTML":"<h1>Hello!</h1>"}]}
as you can see nothing fancy. Unfortunatly when issueing this request I receive the following error response:
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: application/json
request-id: 1dba7669-1318-488a-a416-63fddbdfcda1
client-request-id: 1dba7669-1318-488a-a416-63fddbdfcda1
Duration: 833.8091
Strict-Transport-Security: max-age=31536000
Date: Fri, 04 Jan 2019 15:13:15 GMT
Content-Length: 236
{
"error": {
"code": "generalException",
"message": "General exception while processing",
"innerError": {
"request-id": "1dba7669-1318-488a-a416-63fddbdfcda1",
"date": "2019-01-04T15:13:16"
}
}
}
When I remove the webparts property from my initial requests the POST succeeds I get response like this:
{"#odata.context":"https://graph.microsoft.com/beta/$metadata#sites('tenant.com%2Cee2667f8-2bae-460e-944b-613773baaa03%2C8c0054a6-6e0e-49cd-be6d-4c4c0aaf644e')/pages/$entity","eTag":"\"{DA2C2C0C-2222-4F11-917E-7B4BBFE8AC99},3\"","id":"da2c2c0c-2222-4f11-917e-7b4bbfe8ac99","lastModifiedDateTime":"2019-01-04T15:08:12Z","name":"Testpagina2.aspx","webUrl":"SitePages/Testpagina2.aspx","title":"Testpagina2","pageLayout":"Article","parentReference":{"siteId":"ee2667f8-2bae-460e-944b-613773baaa03"},"contentType":{"id":"0x0101009D1CB255DA76424F860D91F20E6C411800A19AB965C0D2B54C82DFCC03DBE6A732","name":"Sitepagina"},"publishingState":{"level":"checkout","versionId":"0.1"}}
But ofcourse I would like to add at least some content ( html ) to the page before I publish it.
Could someone tell me if the creation of pages using Graph is not yet fully functional? Or that I'm missing something.
p.s. what kind of webparts are available?

Unfortunately we have a bug in our docs (assigned to be fixed), the "innerHTML" property should be wrapped in a "data" property like the properties of other web parts. Here's what your payload should look like:
{
"name":"Testpage21.aspx",
"publishingState":{"level":"published","versionId":"0.1"},
"title":"Testpage21",
"webParts": [{
"type":"rte",
"data": {
"innerHTML":"<h1>Hello!</h1>"
}
}]
}
In terms of what web parts are available any part should work but we have not documented the data structures associated with them for the current Beta release. That generally makes the API most useful with your own custom web parts where you already know what properties you need to have in the data block.

Related

SharePoint REST API Online batch request issues : getting 400 Bad Request, odata.error Invalid request

I'm having a bit of trouble isolating a batch request using the _api/$batch request. I'm sure there is just some simple mistake/issue going on, but I can't just pinpoint this. Any ideas?
Here are some snippets of the raw postman console logs for the request:
POST /_api/$batch HTTP/1.1
Accept: application/json; odata=nometadata
Content-Type: multipart/mixed; boundary="batch_8215457c-c4fb-432a-abf6-7b1f86168c65"
Authorization: Bearer <token deleted>
--batch_8215457c-c4fb-432a-abf6-7b1f86168c65
Content-Type: multipart/mixed; boundary="changeset_d9097ba9-2d69-40ca-a301-90cf97aafb17"
Content-Transfer-Encoding: binary
--changeset_d9097ba9-2d69-40ca-a301-90cf97aafb17
Content-Type: application/http
Content-Transfer-Encoding: binary
DELETE https://myOrg.sharepoint.com/sites/mySite/_api/web/lists/getByTitle(myList)/items(27) HTTP/1.1
If-Match: *
Accept: application/json; odata=nometadata
--changeset_d9097ba9-2d69-40ca-a301-90cf97aafb17
Content-Type: application/http
Content-Transfer-Encoding: binary
DELETE https://myOrg.sharepoint.com/sites/mySite/_api/web/lists/getByTitle(myList)/items(30) HTTP/1.1
If-Match: *
Accept: application/json; odata=nometadata
--changeset_d9097ba9-2d69-40ca-a301-90cf97aafb17--
--batch_8215457c-c4fb-432a-abf6-7b1f86168c65--
The response I get back for each item to be deleted is 400 Bad Request with each Batch response also containing:
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"Invalid request."}}}
--batchresponse_38add954-a201-4857-a6db-68067eb9bc0a
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 400 Bad Request
CONTENT-TYPE: application/json;odata=nometadata;streaming=true;charset=utf-8
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"Invalid request."}}}
--batchresponse_38add954-a201-4857-a6db-68067eb9bc0a
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 400 Bad Request
CONTENT-TYPE: application/json;odata=nometadata;streaming=true;charset=utf-8
{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"Invalid request."}}}
--batchresponse_38add954-a201-4857-a6db-68067eb9bc0a--
I've been digging and have tried a few things:
Tried removing the "Accept: application/json; odata=nometadata" from each changeset
Tried adjusting any newlines after requests content-type/encoding
I have tried executing one item in the batch as a single delete request (works)
compared some notes/examples: (Andrew Connell blog: https://gist.github.com/andrewconnell/dcd89e694475b628d0c7)
Can a helpful eye point out the mistake?
This was a bad interpretation of the documentation on my part.
According to Microsoft's documentation, the section on the Request URL states (emphasis mine):
The request URL consists of the root service URL and the $batch option; for example, https://fabrikam.sharepoint.com/_api/$batch or https://fabrikam.office365.com/api/v1.0/me/$batch.
However, the "root service URL" is a bit misleading, as it's actually supposed to be the site's URL. I would have considered the root service URL:
https://myorg.sharepoint.com
So, in my example above, it's:
POST <siteURL>/_api/$batch
Or, more specific to the example:
POST https://yourorg.sharepoint.com/sites/mySite HTTP/1.1
Thanks for everyone who put some thought into this.

DocuSign - Unable to convert document

We’re getting an error – “unable to convert document” for one of our clients on our multi-tenant server. I’ve had a rummage and it looks like that error is generated when you’re sending a file with an unexpected extension meaning that DocuSign doesn’t know how to convert it to a PDF (https://stackoverflow.com/questions/53771197/docusign-random-unable-to-convert-document-error). What I’m failing to understand is how it can be working for some – it works for me on our multi-tenant server – but not others. Is there more to this than meets the eye or am I missing something?
Headers : X-RateLimit-Reset: 1573833600
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 991
X-DocuSign-TraceToken: #####
Strict-Transport-Security: max-age=31536000; includeSubDomains
Cache-Control: no-cache
Date: Fri, 15 Nov 2019 15:20:40 GMT
Response stream : {
"errorCode": "UNABLE_TO_CONVERT_DOCUMENT",
"message": "System was unable to convert this document to a PDF. Unable to convert Document(2019.11.15_NDA - MyDocument) to a PDF. Error: UserId:##### IPAddress:##### Source:ApiRESTv2:FileType 15_nda - my document is ineligible for conversion."
}
Check that you are setting the fileExtension attribute to pdf in the document object in your Envelopes::create call.
If you don't set it, DocuSign does some guessing, but setting the attribute explicitly is the way to go.

PDF.JS Cross Domain

I am attempting to use PDF.JS in order to render user's PDFs in the browser.
We store the PDF files in Azure Blob Storage and we have CORS & SAS to allow our front-end to interact directly with Blob for upload/download.
I have tested our setup with Chrome, Firefox, and Safari, and Chrome is the only browser to fail retrieving the file. The errors I get are related to unsafe headers, the exception below I know results from the inability to read the Content-Range header.
Refused to get unsafe header "Content-Encoding"
Refused to get unsafe header "Content-Range"
Uncaught TypeError: Cannot read property '1' of null
at NetworkManager_onStateChange [as onStateChange]
The response headers from Azure look like:
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Accept-Ranges,Content-Range,Content-Encoding,Content-Length
Cache-Control: max-age=1209600
Content-Disposition: attachment; filename=tracemonkey.pdf
Content-Length: 65536
Content-Range: bytes 0-65535/1016315
Content-Type: application/pdf
Date: Tue, 09 May 2017 15:31:33 GMT
Etag: "0x8D49632DD6406EC"
Last-Modified: Mon, 08 May 2017 16:54:17 GMT
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-blob-type: BlockBlob
x-ms-lease-state: available
x-ms-lease-status: unlocked
x-ms-request-id: 56258985-0001-0062-15d9-c8130c000000
x-ms-server-encrypted: false
x-ms-version: 2015-12-11
This is our setup for Blob Storage
Can anyone help me figure out what additional configuration I need to provide to Azure Blob Storage to get this working in Chrome?
set this rules,working on same issue
<Cors>
<CorsRule>
<AllowedOrigins>http://www.contoso.com, http://www.fabrikam.com</AllowedOrigins>
<AllowedMethods>PUT,GET,POST</AllowedMethods>
<AllowedHeaders>x-ms-meta-abc,x-ms-meta-data*,x-ms-meta-target*</AllowedHeaders>
<ExposedHeaders>x-ms-meta-customheader,x-ms-meta-data*</ExposedHeaders>
<MaxAgeInSeconds>200</MaxAgeInSeconds>
</CorsRule>
<Cors>
So this was a bit of PEBKAC. I will leave my settings here for anyone else that comes along. We had an application running that set ExposedHeaders=* and AllowedHeaders=* every time we would new our blob service class. So, every time I went into our portal to update the configs, the app would come in after me and change it back.
The settings that work are as follows:
{
Cors: {
CorsRule: [
{
AllowedOrigins: [‘*’],
AllowedMethods: [‘GET’, ‘PUT’, ‘DELETE’],
AllowedHeaders: [‘Accept-Ranges’, ‘Content-Encoding’, ‘Content-Length’, ‘Content-Type’, ‘Range’, ‘Authorization’,'x-ms-blob-content-type', 'x-ms-blob-type', 'x-ms-version'], // x-ms headers for upload
ExposedHeaders: [‘Accept-Ranges’, ‘Content-Range’, ‘Content-Encoding’, ‘Content-Length’, ‘Content-Type’],
MaxAgeInSeconds: Constants.timeout,
},
],
},
}
Thanks #async5 for the help.

Gmail REST api batch support for getting messages

We need to switch from google client library to Gmail REST api in our project, and I've encountered a problem with batch() because it is not available in REST api - you can only get list of ids of messages and then get each message one by one using it's id.
If we use that gmail library everything seems to be clear. We create a batch object and then queue each GET request inside of it. We don't have to care how it's implemented inside.
At the moment I'm trying to do some POC and I'm testing these suggestions https://developers.google.com/gmail/api/guides/batch
with Postman but with no luck..
I'm getting 400 bad request.
How should a proper request body look like in Postman (or other application)?
The next step will be implementing multipart request in Java and sending POST using RestTemplate but I need to present some POC in Postman first.
I'm setting it like on this screenshot ->
Postman
What am I doing wrong?:)
You are close. Here is a working example:
Request
POST https://www.googleapis.com/batch
Content-Type: multipart/mixed; boundary="foo_bar"
Authorization: Bearer {ACCESS_TOKEN}
--foo_bar
Content-Type: application/http
GET /gmail/v1/users/me/messages/152d10540c21bd07
--foo_bar
Content-Type: application/http
GET /gmail/v1/users/me/messages/152d1050d666d7ad
--foo_bar--
Response
--batch_7Xp52oGIwpA_AAEAc7ERnGU
Content-Type: application/http
HTTP/1.1 200 OK
ETag: "A-DdBGA6g-wV4rIZCu5Hcm3JQpY/w2hzEg9kqXFH7AEJ-oSc-y10HNQ"
Content-Type: application/json; charset=UTF-8
Date: Thu, 11 Feb 2016 16:02:06 GMT
Expires: Thu, 11 Feb 2016 16:02:06 GMT
Cache-Control: private, max-age=0
Content-Length: 2809
{
"id": "152d10540c21bd07",
"threadId": "152d1050d666d7ad",
"labelIds": [
"SENT",
"INBOX",
"IMPORTANT"
],
"snippet": "Likewise buddy.", ...
}
--batch_7Xp52oGIwpA_AAEAc7ERnGU
Content-Type: application/http
HTTP/1.1 200 OK
ETag: "A-DdBGA6g-wV4rIZCu5Hcm3JQpY/7v2nqQFBDmEHVvEQoboiwSidilE"
Content-Type: application/json; charset=UTF-8
Date: Thu, 11 Feb 2016 16:02:06 GMT
Expires: Thu, 11 Feb 2016 16:02:06 GMT
Cache-Control: private, max-age=0
Content-Length: 1752
{
"id": "152d1050d666d7ad",
"threadId": "152d1050d666d7ad",
"labelIds": [
"SENT",
"INBOX",
"IMPORTANT"
],
"snippet": "Nice to meet you.", ...
}
--batch_7Xp52oGIwpA_AAEAc7ERnGU--
You don't have to specify the host in each part of the batch, and giving the access token in the Authorization header is enough. You don't have to specify the Content-Length yourself, and don't forget to wrap you boundary string with ".
Then you just have to parse the JSON of each part and you are done.
You need to include gmail/v1 on the POST URL and on each request.
Don't forget about the " around your boundary on the Content-Type header.
See original batch gmail requests documentation: https://developers.google.com/gmail/api/guides/batch
The following worked for me:
POST /batch/gmail/v1 HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {YOUR_ACCESS_TOKEN}
Content-Type: multipart/mixed; boundary="foo_bar"
--foo_bar
Content-Type: application/http
GET /gmail/v1/users/me/messages/1732ebdcb9b8cccf
--foo_bar
Content-Type: application/http
GET /gmail/v1/users/me/messages/1732ecadae4907e2
--foo_bar--
Creating request with Postman - body screenshot
Creating request with Postman - headers screenshot
Just wanted to say that Lucila's answer is now the correct one - the global (https://www.googleapis.com/batch) endpoint is now deprecated, and you must make a post request to your request-specific endpoint (https://www.googleapis.com/batch/gmail/v1 for gmail, for instance).
See this link for additional context.
Apologies for making a new answer for this, I don't have enough reputation to leave a comment.

HttpResult or HttpError with response dto does not get serialized into body

i am trying to return a BadArguments Error along with a custom DTO in the body:
var result = new HttpResult(response, "application/json", HttpStatusCode.BadRequest);
I have tried to use HttpError, HttpResult, setting the response by hand etc etc but i get only
HTTP/1.1 400 BadRequest
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ServiceStack/3,22 Win32NT/.NET
X-Powered-On: ITDEVELOP36-PC
Test-Header-ValidationError: TestValidationError
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 26 Feb 2015 10:36:12 GMT
b
Bad Request
0
No body, no content type is set. What am i missing?
ServiceStack version is 3.3.6.29935.
After poking a while i have found that the ServiceStack framework works just fine. Even in the older version we are using.
The issue exist only when the web.config enables the section.
After removing this section all worked well.

Resources