I have a company with different local services.
Is it a good practice to put LocalBusiness schema for each service subpage like this:
"#context" : "http://schema.org",
"#type" : "LocalBusiness",
"name" : "Service 1 title",
"description": "service 1 description",
"image" : [ "https://mywebsitehere.com/images/service_1.jpg"],
"url" : "https://mywebsitehere.com/offer/service_1/",
and next services like:
"#context" : "http://schema.org",
"#type" : "LocalBusiness",
"name" : "Service 2 title",
"description": "service 2 description",
"image" : [ "https://mywebsitehere.com/images/service_2.jpg"],
"url" : "https://mywebsitehere.com/offer/service_2/",
All other properties like: Address, Geo, Phone, Email, Logo, OpeningHours, hasMap etc will be the same for all subpages.
Will these ld-json schemas help with gaining google rich snippets for my website services pages?
Google does not support structured data for services for rich snippets. However, this does not mean that Google will simply discard your (presumably relevant) structured data. This data may work for voice searches and maybe scraped by the Google Knowledge Graph API.
Google requires structured data to represent each separate content that the data refers to:
Your structured data must be a true representation of the page
content.
Thus, if your web page content represents a local business, use the type LocalBusiness. The same applies to the page providing the service.
Related
As an example imagine a dynamic pricing system which you can ask for offers moving boxes from 1 place to another. Since the price does not exist before you ask for it it's not as simple as retrieving data from some data-base, but an actual search process needs to run.
What I often see in such scenario's is a request/response based endpoint:
POST /api/offers
{
"customerId" : "123",
"origin" : {"city" : "Amsterdam"},
"destination" : {"city" : "New York"},
"boxes": [{"weight" : 100},{"weight": "200"}]
}
201:
{
"id" : "offerId_123"
"product" : {
"id" : "product_abc",
"name": "box-moving"
}
"totalPrice" : 123.43
}
The request has nothing to do with the response except that one is required to find all information for the other.
The way I interpret "manipulation of resources through representations" I think that this also goes for creation. Following that I would say that one should create the process of searching in stead:
POST /api/offer-searches
{
"request" : {
"customerId" : "123",
"origin" : {"city" : "Amsterdam"},
"destination" : {"city" : "New York"},
"boxes": [{"weight" : 100},{"weight": "200"}]
}
}
201:
{
"id" : "offerSearch_123"
"request" : {
"customerId" : "123",
"origin" : {"city" : "Amsterdam"},
"destination" : {"city" : "New York"},
"boxes": [{"weight" : 100},{"weight": "200"}]
}
offers: [
"id" : "offerId_123"
"product" : {
"id" : "product_abc",
"name": "box-moving"
}
"totalPrice" : 123.43
]
}
Here the request and the response are the same object, during the process it's enhanced with results, but both are still a representation of the same thing, the search process.
This has the advantage of being able to "track" the process, by identifying it it can be read again later. You could still have /api/offers/offerId_123 return the created offer to not have to go through the clutter of the search resource. But it also has quite the trade-off: complexity.
Now my question is, is this first, more RPC like approach something we can even call REST? Or to comply to REST constraints should the 2nd approach be used?
Now my question is, is this first, more RPC like approach something we can even call REST? Or to comply to REST constraints should the 2nd approach be used?
How does the approach compare to how we do things on the web?
For the most part, sending information to a server is realized using HTML forms. So we are dealing with a lot of requests that look something like
POST /efc913bf-ac21-4bf4-8080-467ca8e3e656
Content-Type: application/x-www-form-urlencoded
a=b&c=d
and the responses then look like
201 Created
Location: /a2596478-624f-4775-a490-09edb551a929
Content-Location: /a2596478-624f-4775-a490-09edb551a929
Content-Type: text/html
<html>....</html>
In other words, it's perfectly normal that (a) the representations of the resource are not the information that was sent to the server, but intead something the server computed from the information it was sent and (b) not necessarily of the same schema as the payload of the request... not necessarily even the same media type.
In an anemic document store, you are more likely to be using PUT or PATCH. PATCH requests normally have a patch document in the request-body, so you would expect the representations to be different (think application/json-patch+json). But even in the case of PUT, the server is permitted to make changes to the representation when creating its resource (to make it consistent with its own constraints).
And of course, when you are dealing with responses that contain a representation of "the action", or representations of errors, then once again the response may be quite dissimilar from the request.
TL;DR REST doesn't care if the representation of a bid "matches" the representation of the RFP.
You might decided its a good idea anyway - but it isn't necessary to satisfy REST's constraints, or the semantics of HTTP.
I'm attempting to make correct and efficient use of schema.org json-ld recommandations for adding semantic to a web page.
I have a web page for unique organizations (http://example/organization1):
{
"#context": "http://schema.org/",
"#type": "Organization",
"#id" : "#ID_Organization1",
"name": "Organization1",
"url": "https://myorganization1.com
}
Can I reuse the information on that organization on another page without having to redeclare it ? (http://example/offers)
{
"#context": "https://schema.org/",
"#type": "Review",
"itemReviewed" : {
"#type" : "Organization",
"#id" : "http://example/organization1#ID_Organization1"
},
}
Check the following JSON-LD 1.1 documentation information:
3.3 Node Identifiers
To be able to externally reference nodes
in an RDF graph, it is important that nodes
have an identifier. IRIs are a fundamental concept of Linked Data, for
nodes to be truly linked, dereferencing the identifier should result
in a representation of that node. This may allow an application to
retrieve further information about a node. In JSON-LD, a node is identified using the #id keyword.
This probably means that there is no limit to using this element.
I have recently written json schema for my client's local business with multiple locations. I have run it through Google's Structured Data Testing Tool, but I have noticed that it is defined as "unspecified type" rather than LocalBusiness.
I am also trying to implement this schema onto my client's WordPress site via Google Tag Manager and it has not seemed to work (I am guessing that this is because it is unspecified type rather than LocalBusiness?).
You didn’t post your JSON-LD, but from the output of Google’s SDTT, I would guess that this is the reason:
You’re using graph instead of #graph. Without the #, it gets interpreted as a Schema.org property (which doesn’t exist), not as a way defined in JSON-LD to provide multiple top-level items.
So instead of something like
{
"#context": "http://schema.org",
"graph":
[
{
"#type": "Organization"
},
{
"#type": "LocalBusiness"
}
]
}
you need to have something like
{
"#context": "http://schema.org",
"#graph":
[
{
"#type": "Organization"
},
{
"#type": "LocalBusiness"
}
]
}
I'm attempting to add a schema for an Accommodation, but I can't seem to find a way to reference the 'offer' or 'price' to this schema. Im using JSON-LD to format this schema.
I have also tried room/hotelRoom as an alternative. I also tried using the additionalType value to allow me to use product based options such as offers, but this didn't work.
JSON-LD:
{
"#context": "http://schema.org",
"#type": "Accommodation",
"additionalType": "Product",
"name": "example",
"offers": {
"#type": "Offer",
"name": "1 Night",
"priceSpecification": {
"#type": "PriceSpecification",
"price": 1,
"minPrice": 1,
"maxPrice": 2,
"priceCurrency": "GBP"
}
}
}
Google Structured Data Testing Tool:
The property offers is not recognized by Google for an object of type Accommodation.
How am I meant to add a price to a specific accommodation/room in my schema?
Schema.org intends¹ that authors use MTEs² in this case. That, however, does of course not necessarily mean that all consumers fully support this (yet).
So instead of:
"#type": "Accommodation",
you would use:
"#type": ["Accommodation", "Product"],
(additionalType": "Product", is not needed anymore, so could be removed)
While Google’s Structured Data Testing Tool only displays one type (seems to be always the first value in the array), it reports no errors when using this.
¹ The accommodation documentation does not yet reflect this (the changes are currently part of the draft for the next version), and the topic gets discussed here:
Remove Accommodation from all of the Offer-related schema and use MTEs instead
Hotel examples and documentation must be updated for MTE pattern
² MTE: Multi-Typed Entity.
On forhand : sorry if I misunderstood hypermedia or Restfull concepts : it's a work in progress...)
I try to figure out hypermedia and hydra (http://www.markus-lanthaler.com/hydra), and have some questions about returning information to the client before designing my api.
say I have a webshop located at www.myshop.com
a HTTP GET to the root could return (for example) a list of resources represented as link (in a json-ld document):
...
"#id": "/api",
"products" : "www.myshop.com/api/products",
"customers":"www.myshop.com/api/customers"
...
First question on hydra, how could I add actions here ? it seems the client needs to load another document before the load of application. I mean the potential actions are not in the docuemnt retrieved from www.myshop.com/api Or do I miss something?
Then going further, I've stated that products is a hydra:Link so that the client could follow that link (interact with it) with a HTTP GET and retrieve a list of products. that will be a list like this :
....
{
"#id": "/api/products/123",
"#type": "vocab:Product"
},
{
"#id": "/api/products/124",
"#type": "vocab:Product"
},
....
here the client receives a list of product (That could be a paged collection). But if the client wants to display it to the user, let's say a table with [product Id, price, name] (not all Product's properties)
Second Question : How could I do that without the client sending a request to the server for each product, but still provide the link to get the product's detailed information,(or even here having four link : one for getting the detailed information, one for Delete and one for sharing it with a friend and a last one to add it to a Basket) ?
In fact I have difficulties to figure out how hydra is coming into play by not having Links in the document itself? I think that Hal uses this approach to having links in the document itself (if I am right) and I try to find how hydra does this link...
regards
A bit late but I'll nevertheless try to answer your questions Cedric.
say I have a webshop located at www.myshop.com
a HTTP GET to the root could return (for example) a list of resources
represented as link (in a json-ld document):
... "#id": "/api",
"products" : "www.myshop.com/api/products",
"customers":"www.myshop.com/api/customers" ...
First question on hydra, how could I add actions here ? it seems the
client needs to load another document before the load of application.
I mean the potential actions are not in the docuemnt retrieved from
www.myshop.com/api Or do I miss something?
You basically have two options here: 1) embed the operations directly in the response or 2) attach the operations to the properties (products, customers) instead.
Approach 1) would look somewhat like this:
...
"#id": "/api",
"products" : {
"#id": "http://www.myshop.com/api/products",
"operation": {
"#type": "Operation",
"method": "POST",
"expects": "Product"
}
}
...
While approach 2) would attach the same operation to the products property in the referenced Hydra ApiDocumentation:
...
"#id": "...products",
"supportedOperation": {
"#type": "Operation",
"method": "POST",
"expects": "Product"
}
...
Please note that in 1) I used operation while in 2) I used supportedOperation. Also, you should use a more specific type than Operation.
Regarding your second question:
with a HTTP GET and retrieve a list of products. that will be a list like this :
....
{
"#id": "/api/products/123",
"#type": "vocab:Product"
},
{
"#id": "/api/products/124",
"#type": "vocab:Product"
},
....
here the client receives a list of product (That could be a paged
collection). But if the client wants to display it to the user, let's
say a table with [product Id, price, name] (not all Product's
properties)
Second Question: How could I do that without the client sending a
request to the server for each product, but still provide the link to
get the product's detailed information,(or even here having four link
: one for getting the detailed information, one for Delete and one for
sharing it with a friend and a last one to add it to a Basket) ?
You can add as much information (including links) as you want directly in the collection.
....
{
"#id": "/api/products/123",
"#type": "vocab:Product",
"name": "Product 123",
"price": "9.99"
},
{
"#id": "/api/products/124",
"#type": "vocab:Product",
"name": "Product 124",
"price": "19.99"
},
....
That way, a client only needs to dereference an item if the collection doesn't contain that required information.
In fact I have difficulties to figure out how hydra is coming into
play by not having Links in the document itself?
Of course you do have links in the document as well. Links are just properties whose values happen to be URLs (objects with an #id property unless you set the property's type to #id in the context to get rid of that) instead of treating them specially.
note: The Hydra part of the answers I am not so sure, the JSON-LD and REST are okay I think.
You can use #base and relative IRIs by JSON-LD, or you can define namespaces in the #context, so after that you can use relative IRIs as ns:relativeIRI. Each one is better than returning the full IRI. (It is easier to parse the results with a general JSON-LD parser on client side, instead of a simple JSON parser.)
You can define your own #vocab using the Hydra vocab, or you can add "action" definitions in the #context. If you want to "add actions" you have to use hydra:Operation sub-classes in your vocab. Something like this (but I am not a Hydra expert):
{
"#id": "vocab:ProductList",
//...
"hydra:supportedOperations": [
{
"#type": "hydra:CreateResourceOperation",
"method": "POST",
"expects": "vocab:Product"
}
//...
]
}
In general by REST, if you need the same resource with fewer properties, then you have to add a new IRI for that resource, e.g.: /myresource?fewer=1. For example in your case: /api/products/?fields="id, price, name" is okay.
By Hydra you have 2 choices if you want multiple links; you can add a new hydra:Link as a property, or you can add a new hydra:Operation as a supportedOperation with method: GET. I guess get operations are for something like search which has an user input, but if you don't want to add a new property for each link, I think you have no other option.
Actually Hydra does have link and operation support. Maybe it is not clear, but JSON-LD is an RDF format, you can define RDF triples in that. So the IRIs you used for example by "customers":"www.myshop.com/api/customers" are just resource identifiers and not links. A link should have IRI, title, method(GET), language, content-type, iana:relation, etc... so it is not possible to describe a link you can follow with just a single IRI (resource identifier). By processing a REST resource a client should never check the IRI structure to know how to display what it got from you. You have to check the other properties of the links, especially iana:relations or by Hydra maybe operation type to do that. So for example in your case www.myshop.com/api/dav8ufg723udvbquacvd723fudvg is a perfectly valid IRI for the list of the customers. We use nice IRIs only because it is easier to configure generate them on server side, and configure a router for them.
Please check the Hydra vocab before further questions. As you can see a Class can have supportedOperations and supportedProperties which are both collections. A Link is a Property sub-class which can have a single Operation. By collections I think you have to use the Collection class, in which member contains the items of the collection... Be aware that by JSON-LD there is no difference by defining a single item or multiple items with the same type. In the context you have to define only the type, and the value of the property can contain both a single item or an array of items... If you want some constraints about that I guess you have to add some OWL triples, and a validator which checks the values using them.