Gmail Email Markup not working with Amazon SES - email

I'm trying to send a e-mail with event markup to my guests but I'm having no success. I'm using Amazon SES to send e-mail but neither Gmail nor Inbox is showing the invite. I believe I setup the Amazon SES with the right DKIM-Signature and link my personal gmail with SES.
The full e-mail received is below
Delivered-To: xxxx#gmail.com
Received: by 10.107.136.164 with SMTP id s36csp123199ioi;
Wed, 27 Jan 2016 14:05:16 -0800 (PST)
X-Received: by 10.55.75.85 with SMTP id y82mr38139956qka.29.1453932315743;
Wed, 27 Jan 2016 14:05:15 -0800 (PST)
Return-Path: <00000152851e818e-5dd6f0af-7707-4e18-b278-f918cd14773c-000000#amazonses.com>
Received: from a8-88.smtp-out.amazonses.com (a8-88.smtp-out.amazonses.com. [54.240.8.88])
by mx.google.com with ESMTPS id t4si8059067qht.13.2016.01.27.14.05.15
for <xxxx#gmail.com>
(version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128);
Wed, 27 Jan 2016 14:05:15 -0800 (PST)
Received-SPF: pass (google.com: domain of 00000152851e818e-5dd6f0af-7707-4e18-b278-f918cd14773c-000000#amazonses.com designates 54.240.8.88 as permitted sender) client-ip=54.240.8.88;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of 00000152851e818e-5dd6f0af-7707-4e18-b278-f918cd14773c-000000#amazonses.com designates 54.240.8.88 as permitted sender) smtp.mailfrom=00000152851e818e-5dd6f0af-7707-4e18-b278-f918cd14773c-000000#amazonses.com;
dkim=pass header.i=#amazonses.com;
dmarc=fail (p=NONE dis=NONE) header.from=gmail.com
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple;
s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug; d=amazonses.com; t=1453932315;
h=From:Reply-To:To:Subject:MIME-Version:Content-Type:Message-ID:Date:Feedback-ID;
bh=Tcg1kQlJP4+u0X7GdV2QjlipSG+mgyFwieDIo8nh/7U=;
b=XAv/G3O/QLg0qrrxctppcY7yvB/oOizgL3BNLM1LSizltSmykmywLFgTNvuwMTUH
zNJJYI6mz6gk5d5jlkS3kx25owYjL/WCq4QRybPlVTJtVvuvyKcFW9MBw7RWBcEfIQL
PYhrLy214VmxHsi1uVQUtwKvjFRAst1rDAOlenq8=
From: =?UTF-8?B?RXNkcmFzIGUgTGlhIA==?= <xxxx#gmail.com>
Reply-To: xxxx#gmail.com
To: xxxx#gmail.com
Subject: Subject
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_24077334_1650467526.1453932315024"
Message-ID: <00000152851e818e-5dd6f0af-7707-4e18-b278-f918cd14773c-000000#email.amazonses.com>
Date: Wed, 27 Jan 2016 22:05:15 +0000
X-SES-Outgoing: 2016.01.27-54.240.8.88
Feedback-ID: 1.us-east-1.LtLhfWkGZbBzQf+J9gUX7yOKQsymo3nzRJ+0IQqaHIo=:AmazonSES
------=_Part_24077334_1650467526.1453932315024
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
{
"#context" : "http://schema.org",
"#type" : "EventReservation",
"reservationNumber" : "1",
"reservationStatus": "http://schema.org/Confirmed",
"reservationFor" : {
"#type" : "Event",
"name" : "Title",
"startDate" : "2016-04-16T15:00",
"location" : {
"#type" : "Place",
"name" : "Name",
"address" : {
"#type" : "PostalAddress",
"streetAddress" : "Address",
"addressLocality" : "City",
"addressRegion" : "Region",
"addressCountry" : "Country",
"postalCode" : "13030320"
}
}
},
"underName" : {
"#type" : "Person",
"name" : "Name"
}
}
Email-message
------=_Part_24077334_1650467526.1453932315024
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<script type=3D"application/ld+json">
{
"#context" : "http://schema.org",
"#type" : "EventReservation",
"reservationNumber" : "1",
"reservationStatus": "http://schema.org/Confirmed",
"reservationFor" : {
"#type" : "Event",
"name" : "Title",
"startDate" : "2016-04-16T15:00",
"location" : {
"#type" : "Place",
"name" : "Name",
"address" : {
"#type" : "PostalAddress",
"streetAddress" : "Address",
"addressLocality" : "City",
"addressRegion" : "Region",
"addressCountry" : "Country",
"postalCode" : "13030320"
}
}
},
"underName" : {
"#type" : "Person",
"name" : "Name"
}
}
</script>
<br/>Email-Message
------=_Part_24077334_1650467526.1453932315024--

Your email encoding is
Content-Transfer-Encoding: quoted-printable
Thus all '=' signs will become '=3D'.
In your case:
<script type=3D"application/ld+json">
which it seems does not play well with gmail email markup.
Try to use this as a test tool and try with and without 3D
You will see that w/out 3D it will work and with 3D it will not

Related

Is it safe to send ODATA rest batch requests in HTTPS Body via POST and get response in the same

We are planning use below rest request for SAP-Successfactor, which send bulk request at a time in Body
Please find Example below :
OData API POST Request : https://<>/odata/v2/$batch
Body Start :
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding: binary
GET getUsersByDynamicGroup?groupId=6119L&$format=json HTTP/1.1
Content-Type: application/json;charset=UTF-8
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding: binary
GET getUsersByDynamicGroup?groupId=6000L&$format=json HTTP/1.1
Content-Type: application/json;charset=UTF-8
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding: binary
GET getUsersByDynamicGroup?groupId=1588L&$format=json HTTP/1.1
Content-Type: application/json;charset=UTF-8
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding: binary
GET getUsersByDynamicGroup?groupId=1234L&$format=json HTTP/1.1
Content-Type: application/json;charset=UTF-8
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding: binary
GET getUsersByDynamicGroup?groupId=123L&$format=json HTTP/1.1
Content-Type: application/json;charset=UTF-8
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
Body End :
Response in Body :
--batch_c96b193b-b98c-4a4b-b479-696536f72239
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
Content-Length: 133
{
"d" : [
{
"firstName" : "Automation", "lastName" : "User9", "middleName" : "Test", "userId" : "103272", "userName" : "103272"
}
]
}
--batch_c96b193b-b98c-4a4b-b479-696536f72239
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
Content-Length: 127
{
"d" : [
{
"firstName" : "Ava", "lastName" : "Johnston", "middleName" : null, "userId" : "ajohnston", "userName" : "Ava"
}
]
}
When we send request in Post, I know its secure
but still I was just thinking is safe to do all this ?
Please ignore me I am asking some basic question .
Please enlighten me if you have something to share regarding this.

Paypal "Create a Payment Resource" doesn't work ( 401 Unauthorized)

I try to implement paypal. I'm doing the official tutorial and now I'm stuck on "Create a Payment Resource"
Sample Request is:
curl -v https://api.sandbox.paypal.com/v1/payments/payment \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {accessToken}' \
{
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"transactions": [{
"amount": {
"total": "21.50",
"currency": "EUR",
"details": {
"subtotal": "15.00",
"tax": "2.00",
"shipping": "2.50",
"handling_fee": "1.00",
"shipping_discount": "-1.00",
"insurance": "2.00"
}
},
"description": "This is the payment transaction description.",
"custom": "This is a hidden value",
"invoice_number": "unique_invoice_number",
"soft_descriptor": "your order description",
"item_list": {
"items": [{
"name": "Item 1",
"description": "add description here",
"quantity": "2",
"price": "10.00",
"sku": "1",
"currency": "EUR"
},
{
"name": "Voucher",
"description": "discount on your order",
"quantity": "1",
"price": "-5.00",
"sku": "vouch1",
"currency": "EUR"
}
]
}
}],
"note_to_payer": "Contact us for any questions on your order.",
"redirect_urls": {
"return_url": "http://example.com/success",
"cancel_url": "http://example.com/cancel"
}
}
I changed the -{accessToken} with my access token:
curl -v https://api.sandbox.paypal.com/v1/payments/payment \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {A21AAHxasde3pBCINcYK6_VkHF2Y2M6dZIGRrvWBHKn1-0A9njg73e3KzrHAL94rVtPOOacMZzyzh-AqSagXEvGT6oY3C4UIsg}' \
{
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"transactions": [{
"amount": {
"total": "21.50",
"currency": "EUR",
"details": {
"subtotal": "15.00",
"tax": "2.00",
"shipping": "2.50",
"handling_fee": "1.00",
"shipping_discount": "-1.00",
"insurance": "2.00"
}
},
"description": "This is the payment transaction description.",
"custom": "This is a hidden value",
"invoice_number": "unique_invoice_number",
"soft_descriptor": "your order description",
"item_list": {
"items": [{
"name": "Item 1",
"description": "add description here",
"quantity": "2",
"price": "10.00",
"sku": "1",
"currency": "EUR"
},
{
"name": "Voucher",
"description": "discount on your order",
"quantity": "1",
"price": "-5.00",
"sku": "vouch1",
"currency": "EUR"
}
]
}
}],
"note_to_payer": "Contact us for any questions on your order.",
"redirect_urls": {
"return_url": "http://example.com/success",
"cancel_url": "http://example.com/cancel"
}
}
When I run this in console, I get
Trying 173.0.82.78...
* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#0)
* found 148 certificates in /etc/ssl/certs/ca-certificates.crt
* found 597 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / RSA_AES_256_CBC_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: api.sandbox.paypal.com (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #3
* subject: C=US,ST=California,L=San Jose,O=PayPal\, Inc.,OU=PayPal Production,CN=api.sandbox.paypal.com
* start date: Tue, 21 Aug 2018 00:00:00 GMT
* expire date: Thu, 20 Aug 2020 12:00:00 GMT
* issuer: C=US,O=DigiCert Inc,CN=DigiCert Global CA G2
* compression: NULL
* ALPN, server did not agree to a protocol
> GET /v1/payments/payment HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> Authorization:Bearer {A21AAHxasde3pBCINcYK6_VkHF2Y2M6dZIGRrvWBHKn1-0A9njg73e3KzrHAL94rVtPOOacMZzyzh-AqSagXEvGT6oY3C4UIsg}
>
< HTTP/1.1 401 Unauthorized
< Date: Tue, 27 Nov 2018 08:33:03 GMT
< Server: Apache
< paypal-debug-id: 3711056ae62c6
< HTTP_X_PP_AZ_LOCATOR: sandbox.slc
< Paypal-Debug-Id: 3711056ae62c6
< Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.API.1%26silo_version%3D1880%26app%3Dapiplatformproxyserv%26TIME%3D1057095003%26HTTP_X_PP_AZ_LOCATOR%3Dsandbox.slc; Expires=Tue, 27 Nov 2018 09:03:03 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
< Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
< Vary: Authorization
< Content-Length: 83
< Connection: close
< Content-Type: application/json
<
So, why doesn't it authorize my token? Problem with syntax, or do I miss something completely relevant?
Thanks for your help
Cheers Tim
Try getting rid of the {}'s around your token value. It should just be:
Bearer A21AAHxasde3pBCINcYK6_VkHF2Y2M6dZIGRrvWBHKn1...

Google (inbox, gmail, now) doesn't recognize EventReservation

I'm adding EventReservation JSON-LD into email (sent from me to me using gmail API from Chrome Extension).
It is successfully delivered into my inbox, but google doesn't recognize this as an event. Here it is email body dump from delivered email (HTML part is successfully validated by google structured data testing tool and yandex structured data validator, and actually json is copy-pasted from an real event that was parsed in my Inbox, so script should be good):
Received: from 236444161893
named unknown
by gmailapi.google.com
with HTTPREST;
Sat, 26 Mar 2016 07:34:52 -0400
From: XXXXXXX#gmail.com
To: XXXXXXX#gmail.com
Subject: Lets Celebrate !
Content-Type: text/html; charset="utf-8"
Date: Sat, 26 Mar 2016 07:34:52 -0400
Message-Id: <CAEY7X7rQZFQTmYqyH-UEMt5KR3bwbC5D-KhT3Rv8vKixVrGkFA#mail.gmail.com>
<html>
<head>
<title>Sample Title</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "123123123",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationStatus": "http://schema.org/Confirmed",
"reservationFor": {
"#type": "Event",
"name": "ProductCamp Helsinki 2016",
"startDate": "2016-04-09T10:00:00+03:00",
"endDate": "2016-04-09T16:00:00+03:00",
"location": {
"#type": "Place",
"name": "OP Headquarters",
"address": {
"#type": "PostalAddress",
"streetAddress": "Teollisuuskatu 1E00510 Helsinki",
"addressLocality": "Helsinki",
"addressRegion": "",
"postalCode": "00510",
"addressCountry": "FI"
}
}
}
}
</script>
<b>I did it!</b>
</body>
</html>
EventReservation Email in my Inbox
What could be wrong?
UPDATE: This HTML works and parsed by Inbox when I send it through script.google.com (MailApp.sendEmail), but doesn't work if it is sent from Chrome Extension using gmail API (POST https://www.googleapis.com/gmail/v1/users/me/messages/send) . So it looks like something wrong with email headers. E.g. "correct" email sent from script.google.com contains DKIM-Signature etc:
Delivered-To: XXXXXXX#gmail.com
Received: by 10.31.52.16 with SMTP id b16csp631299vka;
Sat, 26 Mar 2016 05:40:04 -0700 (PDT)
X-Received: by 10.31.58.139 with SMTP id h133mr9599567vka.158.1458996004694;
Sat, 26 Mar 2016 05:40:04 -0700 (PDT)
Return-Path: <3JIP2VgkJCcEiluklyzwinthps.jvtiluklyzwinthps.jvt#maestro.bounces.google.com>
Received: from mail-vk0-x245.google.com (mail-vk0-x245.google.com. [2607:f8b0:400c:c05::245])
by mx.google.com with ESMTPS id g188si4468255vkf.94.2016.03.26.05.40.04
for <XXXXXXX#gmail.com>
(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
Sat, 26 Mar 2016 05:40:04 -0700 (PDT)
Received-SPF: pass (google.com: domain of 3JIP2VgkJCcEiluklyzwinthps.jvtiluklyzwinthps.jvt#maestro.bounces.google.com designates 2607:f8b0:400c:c05::245 as permitted sender) client-ip=2607:f8b0:400c:c05::245;
Authentication-Results: mx.google.com;
dkim=pass header.i=#gmail.com;
spf=pass (google.com: domain of 3JIP2VgkJCcEiluklyzwinthps.jvtiluklyzwinthps.jvt#maestro.bounces.google.com designates 2607:f8b0:400c:c05::245 as permitted sender) smtp.mailfrom=3JIP2VgkJCcEiluklyzwinthps.jvtiluklyzwinthps.jvt#maestro.bounces.google.com;
dmarc=pass (p=NONE dis=NONE) header.from=gmail.com
Received: by mail-vk0-x245.google.com with SMTP id e6so159765935vkh.0
for <XXXXXXX#gmail.com>; Sat, 26 Mar 2016 05:40:04 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20120113;
h=mime-version:message-id:date:subject:from:to;
bh=AcafBmWjtt8pobLyfk/O93P08+xv/A6AO4gP7r6A0pI=;
b=ZXfhpJnohG6skmBxr4JFYf/743Sy7ckO7PnyUBXytwPNwh3GoULK+LJAyXloqt4hBs
7aoKDtuFsr4o2Q2Q+fexqw3qY8QheK/FG7Mr2lVAfVMDg56tumRIp27B4XmaNyL96S3k
i35hR5B5trQKU/qFENnXCQc5LjFdDLUADzbrs6VMHLZW8I/73Yq7+/JDkHeMmIZMAboz
KN8qyWaFZSJvMGg3NTkurkpBE5oJ6KxCN6cjZKLoUFfbPaqa9cdc0c7w4+fNFK0DzjPT
ESsDEpxS9K/1ZL70xYpUmrBzaIhoOehRfpZRc+P4gXAaPvo36PC1ZJjmgzRD6etHJKSM
VB2w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20130820;
h=x-gm-message-state:mime-version:message-id:date:subject:from:to;
bh=AcafBmWjtt8pobLyfk/O93P08+xv/A6AO4gP7r6A0pI=;
b=gB2OQWkIc7u6mfjc5l9T6umyFBasInqetcEHqQcXbuymmKS5DpqDE8MwYpI62OmVWV
gqrP3E+lf43acVMjslMWQUXuXJQctZMEKkehiN7eA2QeUQd35vWKpjXpuFRBHHLIcin2
XNC8WqwF95XGITPKI9kG78XhdS8h+BVmxVws/rRUA7yqgP/gALPZzeks70Q1p6dh1zkj
Z88ucz2OeOM55EiFha6gKbuLr+0RfZDsquopvxipJjaJhHkcdLqW9xfLf/kgSvD9PdiL
NMJYsnIcgLZ02VtV0RjgK0+/9M/SPtB28nncx8wqP0Z2/fY1MiH+uWMmaH3lvNmgoTLQ
3dIQ==
X-Gm-Message-State: AD7BkJLZUbRwOBaDX4rnT/kKOc5n3NPdUn4PbtoJeh45PKy3qlm7fE9kOBBa5YLgCLErp694wJeXHnGj7LiR2Q==
MIME-Version: 1.0
X-Received: by 10.31.11.75 with SMTP id 72mr11424050vkl.2.1458996004582; Sat,
26 Mar 2016 05:40:04 -0700 (PDT)
Message-ID: <001a1146937894fe1e052ef2fa6a#google.com>
Date: Sat, 26 Mar 2016 12:40:04 +0000
Subject: Test Email markup - Sat Mar 26 2016 15:40:04 GMT+0300 (EAT)
From: XXXXXXX#gmail.com
To: XXXXXXX#gmail.com
Content-Type: multipart/alternative; boundary=001a1146937894fe08052ef2fa67
--001a1146937894fe08052ef2fa67
Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes
I did it!
--001a1146937894fe08052ef2fa67
Content-Type: text/html; charset=ISO-8859-1
<html>
<head>
<title>Sample Title</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "1231231234",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationStatus": "http://schema.org/Confirmed",
"reservationFor": {
"#type": "Event",
"name": "ProductCamp Helsinki 2016",
"startDate": "2016-04-09T10:00:00+03:00",
"endDate": "2016-04-09T16:00:00+03:00",
"location": {
"#type": "Place",
"name": "OP Headquarters",
"address": {
"#type": "PostalAddress",
"streetAddress": "Teollisuuskatu 1E00510 Helsinki",
"addressLocality": "Helsinki",
"addressRegion": "",
"postalCode": "00510",
"addressCountry": "FI"
}
}
}
}
</script>
<b>I did it!</b>
</body>
</html>
--001a1146937894fe08052ef2fa67--
I tried to do the same thing (and asked a similar question) and reached the conclusion that the problem is that Inbox ignores structured data unless the email is authenticated using DKIM (to mitigate against spam). I couldn't work out how to enable authentication using the Gmail API, so I opted for using the Google Apps Script function MailApp.sendEmail() instead, as that does send authenticated emails.

Gmail not recognizing JSON-LD

I am attempting to test Gmail's capabilities to process embedded JSON-LD in an HTML message in order to show the relevant action in the Inbox view, the introduction of which is described here. I have sent myself a message (using the Python API), for which I expect Gmail to render my View Action, an example of which is shown here. However, nothing is happening. I am expecting to see a link for "View File", similar to one that would be displayed for flight reservations, etc.
I'm trying to understand if there is a problem with my particular JSON-LD content, or if I'm trying to do something that isn't supported. The relevant JSON-LD segment, as embedded in the <body>, is this:
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "CreativeWork",
"#id": "http://my-site.com/file/1",
"additionalType": "http://www.productontology.org/id/Computer_file",
"name": "My File",
"description": "View this file",
"url": "http://my-site.com/file/1",
"action": {
"#type": "ViewAction",
"url": "http://my-site.com/file/1",
"name": "View File"
}
}
</script>
In case there is some issue with the way the email is encoded, here it is in raw format (personal info redacted)
Received: from 874510238733-ktbae5ftk223du75th86q0uua7i7rp5v.apps.googleusercontent.com
named unknown
by gmailapi.google.com
with HTTPREST;
Fri, 6 Mar 2015 14:54:52 -0800
Content-Type: multipart/alternative;
boundary="===============5111695568485418487=="
MIME-Version: 1.0
to: ****#gmail.com
subject: A file has been shared to your email
Date: Fri, 6 Mar 2015 14:54:52 -0800
Message-Id: <CADTCK+Vyd-bKWBJXMcs8eS1zQ-b34BanFzNKOBMVf_2dBiPB3A#mail.gmail.com>
From: ****#gmail.com
--===============5111695568485418487==
Content-Type: text/text; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
A new file is available. View this file <http://my-site.com/file/1>
--===============5111695568485418487==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
<html>
<body>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "CreativeWork",
"#id": "http://my-site.com/file/1",
"additionalType": "http://www.productontology.org/id/Computer_file",
"name": "My File",
"description": "View this file",
"url": "http://my-site.com/file/1",
"action": {
"#type": "ViewAction",
"url": "http://my-site.com/file/1",
"name": "View File"
}
}
</script>
<div>A new file is available. View this file</div>
</body>
</html>
--===============5111695568485418487==--

Get a collection of sub-resources at once with JSON-LD and Hydra

In the RESTful Web API book, the authors advise to expose a profile and use a content type which acknowledges link relations. JSON-LD extended by Hydra seem to match these requirements, and I want to use them in the design of my new API.
I am currently stuck with a performance issue. Let say that I have an online bike store, and I want to retrieve information about the wheels of a given bike.
With the Hydra specification, it seems to me that I need to send 2 requests to get the details about the wheels.
The first request is toward the bike itself:
GET /mybike HTTP/1.1
Host: wowbike.com
The response contains a Hydra::Link to the collection of wheels:
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"#context" :
{
"Bike": "/contexts/vocab#Bike"
},
"#id" : "/mybike",
"#type" : "Bike",
"size" : "L",
"wheels" : "/mybike/wheels" // "wheels" is a "hydra:Link"
}
Now I can send a second request to the wheels resource to get the details:
GET /mybike/wheels HTTP/1.1
Host: wowbike.com
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"#context":
{
"Collection": "http://www.w3.org/ns/hydra/core#Collection",
"Wheel" : "/contexts/vocab#Wheel"
},
"#type" : "Collection",
"#id" : "/mybike/wheels",
"member" :
[
{
"#id" : "/mybike/wheels/firstwheel",
"#type" : "Wheel",
"color" : "blue"
},
{
"#id" : "/mybike/wheels/secondwheel",
"#type" : "Wheel",
"color" : "white"
}
]
}
Is it valid to send a single request and get a response such as the one below?
GET /mybike HTTP/1.1
Host: wowbike.com
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"#context" :
{
"Collection": "http://www.w3.org/ns/hydra/core#Collection",
"Bike" : "/contexts/vocab#Bike",
"Wheel" : "/contexts/vocab#Wheel"
},
"#id" : "/mybike",
"#type" : "Bike",
"size" : "L",
"wheels" :
{
"#id" : "/mybike/wheels",
"#type" : "Link",
"member":
[
{
"#id" : "/mybike/wheels/firstwheel",
"#type" : "Wheel",
"color" : "blue"
},
{
"#id" : "/mybike/wheels/secondwheel",
"#type" : "Wheel",
"color" : "white"
}
]
}
}
Great to see that you consider using JSON-LD and Hydra. Of course it is possible to get all the data in a single response. You don't have to change the type of the collection from Collection to Link though. Also, you might want to tweak your context a bit. Summed up, your response would look somewhat like this:
{
"#context": [
"http://www.w3.org/ns/hydra/context.jsonld",
{ "#vocab": "/contexts/vocab#" }
],
"#id": "/mybike",
"#type": "Bike",
"size": "L",
"wheels": {
"#id" : "/mybike/wheels",
"#type" : "Collection",
"member": [
{
"#id" : "/mybike/wheels/firstwheel",
"#type" : "Wheel",
"color" : "blue"
},
{
"#id" : "/mybike/wheels/secondwheel",
"#type" : "Wheel",
"color" : "white"
}
]
}
}
I'm importing Hydra's context here and then overlaying a default vocabulary which means that everything that isn't already defined in Hydra's context is expanded by appending it to /contexts/vocab#. So, Bike for instance will be expanded to /contexts/vocab#Bike.
Btw. there's a W3C Community Groupw working on Hydra which you should join if you are using it. We also have a mailing list on which all your questions will be answered.
The instructions to join the group can be found at http://www.hydra-cg.com/#community