Microsoft Graph API OneNote pages content BadRequest - microsoft-graph-api

I am using OneNote /content endpoint to retrieve page content as described here: https://learn.microsoft.com/en-us/graph/api/page-get?view=graph-rest-1.0
However, calling GET on /me/onenote/pages/{id}/content[?includeIDs=true] returns me this:
{
"error": {
"code": "BadRequest",
"message": "Resource not found for the segment 'content['.",
"innerError": {
"request-id": "6b7e5549-32a5-4b6f-80ed-ecacp9v41699",
"date": "2020-03-31T00:05:27"
}
}
}
calling GET on /me/onenote/pages/{id}/content returns this:
{
"_readableState": {
"objectMode": false,
"highWaterMark": 16384,
"buffer": {
"head": null,
"tail": null,
"length": 0
},
"length": 0,
"pipes": [],
"flowing": null,
"ended": false,
"endEmitted": false,
"reading": false,
"sync": false,
"needReadable": false,
"emittedReadable": false,
"readableListening": false,
"resumeScheduled": false,
"errorEmitted": false,
"emitClose": true,
"autoDestroy": false,
"destroyed": false,
"defaultEncoding": "utf8",
"awaitDrainWriters": null,
"multiAwaitDrain": false,
"readingMore": false,
"decoder": null,
"encoding": null
},
"readable": true,
"_events": {},
"_eventsCount": 5,
"_writableState": {
"objectMode": false,
"highWaterMark": 16384,
"finalCalled": false,
"needDrain": false,
"ending": false,
"ended": false,
"finished": false,
"destroyed": false,
"decodeStrings": true,
"defaultEncoding": "utf8",
"length": 0,
"writing": false,
"corked": 0,
"sync": true,
"bufferProcessing": false,
"writecb": null,
"writelen": 0,
"afterWriteTickInfo": null,
"bufferedRequest": null,
"lastBufferedRequest": null,
"pendingcb": 0,
"prefinished": false,
"errorEmitted": false,
"emitClose": true,
"autoDestroy": false,
"errored": false,
"bufferedRequestCount": 0,
"corkedRequestsFree": {
"next": null,
"entry": null
}
},
"writable": true,
"allowHalfOpen": true,
"_transformState": {
"needTransform": false,
"transforming": false,
"writecb": null,
"writechunk": null,
"writeencoding": null
}
}
Neither returns the actual page content. Any idea?

The "includeIDs" is an optional query parameter. Remove the square brackets around it to get rid of the Bad Request error. So the request should be GET on /me/onenote/pages/{id}/content?includeIDs=true

Related

Microsoft DataVerse WebAPI field/attribute names, logical or shema?

I am currently creating oData queries dynamically to get data out of dataverse. The problem I have is the name for each field/attribute that you specify in the $select query seems to change betweek LogicalName and SchemaName. Is there a way to determine when to use logical and when to use schema? For example, the following query has to use logical for createdby but schema for CreatedByExternalParty
https://xxx.crm11.dynamics.com/api/data/v9.0/accounts(27cacceb-2a0b-ec11-b6e5-0022484220b6)?$select= name &$expand= createdby ( $select= fullname ), CreatedByExternalParty ( $select= fullname )
If I query the EntityDefinition for each of the above two fields, I can't see any difference between them in terms of metadata:
"#odata.type": "#Microsoft.Dynamics.CRM.LookupAttributeMetadata",
"Targets": [
"externalparty"
],
"Format": "None",
"AttributeOf": null,
"AttributeType": "Lookup",
"ColumnNumber": 230,
"DeprecatedVersion": null,
"IntroducedVersion": "8.0.0.0",
"EntityLogicalName": "account",
"IsCustomAttribute": false,
"IsPrimaryId": false,
"IsValidODataAttribute": true,
"IsPrimaryName": false,
"IsValidForCreate": false,
"IsValidForRead": true,
"IsValidForUpdate": false,
"CanBeSecuredForRead": false,
"CanBeSecuredForCreate": false,
"CanBeSecuredForUpdate": false,
"IsSecured": false,
"IsRetrievable": false,
"IsFilterable": false,
"IsSearchable": false,
"IsManaged": true,
"LinkedAttributeId": null,
"LogicalName": "createdbyexternalparty",
"IsValidForForm": true,
"IsRequiredForForm": false,
"IsValidForGrid": true,
"SchemaName": "CreatedByExternalParty",
"ExternalName": null,
"IsLogical": false,
"IsDataSourceSecret": false,
"InheritsFrom": null,
"CreatedOn": "1900-01-01T00:00:00Z",
"ModifiedOn": "1900-01-01T00:00:00Z",
"SourceType": null,
"AutoNumberFormat": "",
"MetadataId": "827e9002-b547-49fc-9e8d-a6b1cfcef33b",
"HasChanged": null,
"AttributeTypeName": {
"Value": "LookupType"
}
"#odata.type": "#Microsoft.Dynamics.CRM.LookupAttributeMetadata",
"Targets": [
"systemuser"
],
"Format": "None",
"AttributeOf": null,
"AttributeType": "Lookup",
"ColumnNumber": 52,
"DeprecatedVersion": null,
"IntroducedVersion": "5.0.0.0",
"EntityLogicalName": "account",
"IsCustomAttribute": false,
"IsPrimaryId": false,
"IsValidODataAttribute": true,
"IsPrimaryName": false,
"IsValidForCreate": false,
"IsValidForRead": true,
"IsValidForUpdate": false,
"CanBeSecuredForRead": false,
"CanBeSecuredForCreate": false,
"CanBeSecuredForUpdate": false,
"IsSecured": false,
"IsRetrievable": false,
"IsFilterable": false,
"IsSearchable": false,
"IsManaged": true,
"LinkedAttributeId": null,
"LogicalName": "createdby",
"IsValidForForm": true,
"IsRequiredForForm": false,
"IsValidForGrid": true,
"SchemaName": "CreatedBy",
"ExternalName": null,
"IsLogical": false,
"IsDataSourceSecret": false,
"InheritsFrom": null,
"CreatedOn": "1900-01-01T00:00:00Z",
"ModifiedOn": "1900-01-01T00:00:00Z",
"SourceType": null,
"AutoNumberFormat": "",
"MetadataId": "b863fe8a-6393-42ec-a540-972d3b45bd7b",
"HasChanged": null,
"AttributeTypeName": {
"Value": "LookupType"
}
Any help would be great, thanks.
I found the answer, with help from users on the dataverse forums, especially Guido Preite for providing the excelent open source tool Dataverse Request Builder
I found the answer from his code, the casing of the CreatedByExternalParty comes from the navigation property when calling RelationshipDefinitions.
/api/data/v9.0/RelationshipDefinitions/Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata?$filter=SchemaName eq 'lk_externalparty_account_createdby'
response:
"ReferencingEntityNavigationPropertyName": "CreatedByExternalParty",

NSwag generate single client class

When using NSwagStudio for generating C# client code (not in file) it generates the way that only one client class and corresponding interface is getting generated with all controllers methods in them.
However when trying to do the same thing with NSwag.MSBuild it generates separate partial classes/interfaces for each controller.
Here is the nswag.json:
{
"openApiToCSharpClient": {
"clientBaseClass": "BillingBaseClient",
"configurationClass": "ConnectionOptions",
"generateClientClasses": true,
"generateClientInterfaces": true,
"clientBaseInterface": null,
"injectHttpClient": true,
"disposeHttpClient": true,
"protectedMethods": [
],
"generateExceptionClasses": true,
"exceptionClass": "ApiException",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": true,
"useBaseUrl": true,
"generateBaseUrlProperty": false,
"generateSyncMethods": false,
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"parameterDateFormat": "yyyy-MM-dd",
"generateUpdateJsonSerializerSettingsMethod": true,
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "BillingClient",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [
],
"additionalContractNamespaceUsages": [
],
"generateOptionalParameters": true,
"generateJsonMethods": true,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [
],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"namespace": "ServiceTitan.Billing.Api.Client",
"requiredPropertiesMustBeDefined": true,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [
],
"excludedParameterNames": [
],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": "BillingClient.g.cs"
}
}
So which option am I missing for telling NSwag to generate single class/interface?
The option you need to change is operationGenerationMode which you have already in your nswag.json file, but you need to change its value to SingleClientFromOperationId if you want to have one interface for multiple controllers. MultipleClientsFromOperationId which is what you currently have set, will generate a class per controller.

Get OData option set values and names

I am using odata api, now I have an attribute on an entity that is an option select like :
attribute name is : status
values are: 1, 2, 3
names: done, progress, new
the thing is when I am using postman to fetch metadata and all I get for the fields 'status' its that its type integer.
Question how do I fetchj option names and values from metadata so I get values and names in response ?
Currently I get this:
<Property Name="status" Type="Edm.Int32">
<Annotation Term="Org.OData.Core.V1.Description" String="" />
</Property>
But I want to get the value and names on response ?
This could be vastly simplified, assuming all you want are the int values, and names for a particular option set attribute of an entity:
GET [Organization URI]/api/data/v8.2/EntityDefinitions(LogicalName='contact')/Attributes(LogicalName='status')/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName&$expand=OptionSet($select=Options),GlobalOptionSet($select=Options)
The $select=LogicalName is just so it doesn't return all the other metadata for the attribute, and the $expand=OptionSet($select=Options) is for local option sets, and the GlobalOptionSet($select=Options) is for Global. If you know what type it is, you can skip it the other, but if you are putting this logic in a shared library (you are aren't you?) then adding both won't hurt:
{
"#odata.context":"http://YourOrg.com/YourInstance/api/data/v8.2/$metadata#EntityDefinitions('new_entity')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata(LogicalName,OptionSet,GlobalOptionSet,OptionSet(Options),GlobalOptionSet(Options))/$entity",
"LogicalName":"new_familyshortname",
"MetadataId":"dc11c01f-b6bd-4664-82d0-3a521841c1f5",
"OptionSet#odata.context":"http://YourOrg.com/YourInstance/api/data/v8.2/$metadata#EntityDefinitions('new_entity')/Attributes(dc11c01f-b6bd-4664-82d0-3a521841c1f5)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet(Options)/$entity",
"OptionSet":null,
"GlobalOptionSet":{
"#odata.type":"#Microsoft.Dynamics.CRM.OptionSetMetadata",
"Options":[
{
"Value":117280000,
"Label":{
"LocalizedLabels":[
{
"Label":"English Value 1",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3cb6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
},
{
"Label":"French Value 1",
"LanguageCode":1036,
"IsManaged":false,
"MetadataId":"d88be67d-4a7d-e411-8890-0050569f1654",
"HasChanged":null
}
],
"UserLocalizedLabel":{
"Label":"English Value 1",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3cb6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
},
"Description":{
"LocalizedLabels":[
{
"Label":"",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3db6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
],
"UserLocalizedLabel":{
"Label":"",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3db6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
},
"Color":null,
"IsManaged":true,
"MetadataId":null,
"HasChanged":null
},
... MORE ...
],
"MetadataId":"dcbbe460-bedb-4985-9a17-2f3dbc637594"
}
}
According to this article this is a multi-step process.
Please note that all the examples use HTTP GET.
First retrieve the entity's MetaData Id (for this example we're using the entity 'account'):
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions?$select=LogicalName,MetadataId&$filter=LogicalName eq 'account'
Returns:
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(LogicalName,MetadataId)",
"value": [{
"LogicalName": "account",
"MetadataId": "70816501-edb9-4740-a16c-6a5efbc05d84"
}]
}
Then retrieve the attribute's MetaDataId (in this example we're using the option set 'customertypecode'):
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)?$select=LogicalName&$expand=Attributes($select=LogicalName;$filter=LogicalName eq 'customertypecode')
Returns:
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(LogicalName,Attributes(LogicalName))/$entity",
"LogicalName": "account",
"MetadataId": "70816501-edb9-4740-a16c-6a5efbc05d84",
"Attributes#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(LogicalName)",
"Attributes": [{
"#odata.type": "#Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
"LogicalName": "customertypecode",
"MetadataId": "4e33af09-ba43-4365-a747-c7e4f9992172"
}]
}
Then query with the entity's and attribute's MetadataIds to get the option set values:
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(4e33af09-ba43-4365-a747-c7e4f9992172)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName&$expand=OptionSet
Returns (truncated at 2 values):
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata(LogicalName,OptionSet)/$entity",
"LogicalName": "customertypecode",
"MetadataId": "4e33af09-ba43-4365-a747-c7e4f9992172",
"OptionSet#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(4e33af09-ba43-4365-a747-c7e4f9992172)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet/$entity",
"OptionSet": {
"MetadataId": "3629e642-b895-41ab-8f1d-ea5bfa30e992",
"HasChanged": null,
"IsCustomOptionSet": false,
"IsGlobal": false,
"IsManaged": true,
"Name": "account_customertypecode",
"ExternalTypeName": null,
"OptionSetType": "Picklist",
"IntroducedVersion": "5.0.0.0",
"Description": {
"LocalizedLabels": [{
"Label": "Type of the account.",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "73f68e38-c78d-48a5-80cb-bee895baab2b",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Type of the account.",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "73f68e38-c78d-48a5-80cb-bee895baab2b",
"HasChanged": null
}
},
"DisplayName": {
"LocalizedLabels": [{
"Label": "Relationship Type",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "e5d47366-fd09-41e6-96a1-cbfdd113b932",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Relationship Type",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "e5d47366-fd09-41e6-96a1-cbfdd113b932",
"HasChanged": null
}
},
"IsCustomizable": {
"Value": true,
"CanBeChanged": false,
"ManagedPropertyLogicalName": "iscustomizable"
},
"Options": [{
"Value": 1,
"Color": null,
"IsManaged": true,
"ExternalValue": null,
"MetadataId": null,
"HasChanged": null,
"Label": {
"LocalizedLabels": [{
"Label": "Competitor",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6c54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Competitor",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6c54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}
},
"Description": {
"LocalizedLabels": [],
"UserLocalizedLabel": null
}
},
{
"Value": 2,
"Color": null,
"IsManaged": true,
"ExternalValue": null,
"MetadataId": null,
"HasChanged": null,
"Label": {
"LocalizedLabels": [{
"Label": "Consultant",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6e54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Consultant",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6e54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}
},
"Description": {
"LocalizedLabels": [],
"UserLocalizedLabel": null
}
}
}
}

How to implement SwiftyJSON to get this data

I've been getting into Swift and I have seen SwiftyJSON is a good library to parse JSON, but still don't know how to use it properly. I need to use SwiftyJSON to get te value of id of every user from this JSON and save them into an array:
{
"users": [
{
"id": 2960784075,
"id_str": "2960784075",
"name": "Jesus Rafael Abreu M",
"screen_name": "chuomaraver",
"location": "",
"profile_location": null,
"url": null,
"description": "",
"protected": false,
"followers_count": 1,
"friends_count": 101,
"listed_count": 0,
"created_at": "Sun Jan 04 19:58:06 +0000 2015",
"favourites_count": 0,
"utc_offset": null,
"time_zone": null,
"geo_enabled": false,
"verified": false,
"statuses_count": 0,
"lang": "es",
"contributors_enabled": false,
"is_translator": false,
"is_translation_enabled": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_image_url": "http://abs.twimg.com/sticky/default_profile_images/default_profile_4_normal.png",
"profile_image_url_https": "https://abs.twimg.com/sticky/default_profile_images/default_profile_4_normal.png",
"profile_link_color": "0084B4",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"default_profile": true,
"default_profile_image": true,
"following": false,
"follow_request_sent": false,
"notifications": false,
"muting": false
},
{
"id": 2959453074,
"id_str": "2959453074",
"name": "lama masarwa",
"screen_name": "LamaMasarwa",
"location": "",
"profile_location": null,
"url": null,
"description": "",
"protected": false,
"followers_count": 7,
"friends_count": 53,
"listed_count": 0,
"created_at": "Mon Jan 05 10:10:46 +0000 2015",
"favourites_count": 0,
"utc_offset": null,
"time_zone": null,
"geo_enabled": false,
"verified": false,
"statuses_count": 2,
"lang": "he",
"contributors_enabled": false,
"is_translator": false,
"is_translation_enabled": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_image_url": "http://pbs.twimg.com/profile_images/552047388873859072/itk5cPx6_normal.png",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/552047388873859072/itk5cPx6_normal.png",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/2959453074/1420454122",
"profile_link_color": "0084B4",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"default_profile": true,
"default_profile_image": false,
"following": false,
"follow_request_sent": false,
"notifications": false,
"muting": false
},...
Could anybody help me to learn how could I do it ?
Thank you very much!
You can parse json like this way.
var IDs: [String] = []
//json is object where users are available
let users = json["users"].arrayValue
users.forEach( {
IDs.append($0["id"].stringValue)
})
print(IDs)
Try this code
let json = "{ \"users\": [{ \"id\": 2960784075, \"id_str\": \"2960784075\" }, { \"id\": 2959453074, \"id_str\": \"2959453074\" } ] }";
if let data = json.data(using: String.Encoding.utf8) {
let json = JSON(data: data)
for item in json["users"].arrayValue {
print(item["id"].stringValue)
}
}
Hope it helps!

Stripe response manipulation in Grails

Hi i have the below response for Stripe in my Grails 2.5.1 application , how i can read and manipulate it using Grails .
Response :
<com.stripe.model.Charge#1467160391 id=ch_17bcduFKvYH0sAt4OMSKjOzA> JSON: { "amount": 7200, "created": 1454790414, "currency": "egp", "id": "ch_17bcduFKvYH0sAt4OMSKjOzA", "livemode": false, "paid": true, "refunded": false, "disputed": null, "captured": true, "description": "customer#sample.org", "statement_description": null, "failure_message": null, "failure_code": null, "amount_refunded": 0, "customer": null, "invoice": null, "refunds": { "data": [], "total_count": 0, "has_more": false, "url": "/v1/charges/ch_17bcduFKvYH0sAt4OMSKjOzA/refunds", "count": null }, "card": null, "dispute": null, "balance_transaction": "txn_17bcduFKvYH0sAt4qSSDZ7Bj", "metadata": {} }

Resources