I am doing some research about JSON-LD. And I found the for the context is in every example used some public schema sites. Can I use my own ?
From:
{
"#context":{
"name": "http://schema.org/name"
}
}
To:
{
"#context":{
"name": "http://my-site.com/name"
}
}
Absolutely. In most cases you will actually need to do that as you probably won't find vocabularies (that's how those "schemas" are generally called) that cover everything you need. If possible, however, you should try to reuse existing vocabularies as it improves interoperabilty and enables code-reuse.
Related
I'm trying to apply HATEOAS to the existing application and I'm having trouble with modeling a form inputs that would be driven by the API response.
The app is allowing to search & book connections between two places. First endpoint allows for searching the connections GET /connections?from={lat,lon}&to={lat,lon}&departure={dateTime} and returns following payload (response body).
[
{
"id": "aaa",
"carrier": "Fast Bus",
"price": 3.20,
"departure": "2019-04-05T12:30"
},
{
"id": "bbb",
"carrier": "Airport Bus",
"price": 4.60,
"departure": "2019-04-05T13:30"
},
{
"id": "ccc",
"carrier": "Slow bus",
"price": 1.60,
"departure": "2019-04-05T11:30"
}
]
In order to make an order for one of connections, the client needs to make a POST /orders request with one of following payloads (request body):
email required
{
"connectionId": "aaa",
"email": "passenger#example.org"
}
email & flight number required (carrier handles only aiprort connections)
{
"connectionId": "bbb",
"email": "passenger#example.org",
"flightNumber": "EA1234"
}
phone number required
{
"connectionId": "ccc",
"phoneNumber": "+44 111 222 333"
}
The payload is different, because different connections may be handled by different carriers and each of them may require some different set of information to provide. I would like to inform the API client, what fields are required when creating an order. The question I have is how do I do this with HATEOAS?
I checked different specs and this is what I could tell from reading the specs:
HAL & HAL-FORMS There are "_templates" but, there is no URI in the template itself. It’s presumed to operate on the self link, which in my case would be /connections... not /orders.
JSON-LD I couldn't find anything about forms or templates support.
JSON-API I couldn't find anything about forms or templates support.
Collection+JSON There is at most one "template" per document, therefore it's presumed that all elements of the collection have the same fields which is not the case in my app.
Siren Looks like the "actions" would fit my use case, but the project seems dead and there are no supporting libraries for many major languages.
CPHL The project seems dead, very little documentation and no libraries.
Ion There is nice support for forms, but I couldn't find any supporting libraries. Looks like it's just a spec for now.
Is such a common problem as having forms driven by the API still unsolved with spec and tooling?
In your example, it appears that Connections are resources. It's not completely clear if Orders are truly resources. I'm guessing probably yes, but to have an Order you need a Client and Connection. So, to create an Order you will need to expose a collection, likely from the Client or Connection, possibly both.
I think the disconnect is from thinking along the lines of "now that we've got a list of available connections, the client can select one and create an Order." That's perfectly valid, but it's remote procedure call (RPC) thinking, not REST. Neither is objectively better than the other, except in the context of a particular set of project requirements, and generally they shouldn't be mixed together.
With an RPC mindset, a create order method is defined (e.g. using OpenAPI) and any clients are expected to use some out-of-band information to determine the correct form required (i.e. by reading the OpenAPI spec).
With a REST/HATEOAS mindset, the correct approach would be to expose a Orders collection from Connection. Each Connection in the collection has a self link and a Orders collection (link or object, as defined by app requirements). Each item of Order has a self link, and that is where the affordances are specified. An Order is a known type (even with REST/HATEOAS the client and service have to at least agree on a shared vocabulary) that the client presumably knows how to define. That vocabulary can be defined using any mechanism that works -- json-ld, XSD, etc.
HATEOAS requires that the result contains everything the client needs to update the state. There can be no out-of-band information (other than the shared vocabulary). So, to solve your issue, you either need to expose a collection of Orders from Connection or you need to allow an Order to be created by posting to Connection. If the latter seems like a bit of a hack, it probably is.
For example, in HAL-Forms, I would do something like:
{
"connections": [{
"id": "aaa",
"carrier": "Fast Bus",
"price": 3.20,
"departure": "2019-04-05T12:30"
"_links": {
"self": { ... }, // link to this connection
"orders": {} // link to collection of orders for this connection
}
},
, ...],
"_links": {
"self": { ... } // link to the collection
},
"_templates": { ... } // post/put/patch/delete connection
}
Clients would follow the links to orders and from there would get the _templates collection that contains the instructions for managing the Order resources. The Order POST would likely require a connection identifier and client information. The HAL-Forms Spec defines a regex property that can be used to specify the type of data to supply for any particular form element. Since you have reached the order by navigating through a specific connection, you would be able to specify in your _templates for that order exactly which fields are required. e.g. /orders?connectionType=aaa would return a different set of required properties than /orders?connectionType=bbb but both use the same self link of /orders?connectionType={type} and you'd validate it on POST/PUT/PATCH.
I should note that the Spring-HATEOAS goes beyond the HAL-Forms spec and allows for multiple _links and _templates. See this GitHub issue.
It may look like HATEOAS/REST requires quite a bit more work than a simple OpenAPI/RPC API and it does. But what you are giving up in simplicity, you are gaining in flexibility and resilience, assuming well-designed clients. Which approach is correct depends on a lot of factors, most of them not technical (team skills, expected consumers, how much control you have over clients, maintenance, etc.).
I currently have the translated English and Japanese .json file in the format:
{
"en": [{
"id": "Cancel",
"defaultMessage": "Cancel"
}, {
"id": "CommonTags",
"defaultMessage": "Common Tags"
}]
"ja": [{
"id": "Cancel",
"defaultMessage": "キャンセル"
}, {
"id": "CommonTags",
"defaultMessage": "共通タグ"
}]}
My question is, why do I need to define the messages now considering that I already have all of these generated and translated? I am simply like to access them in the following way but getting an error:
var messages_ja = require("../../../Resources/Resources.ja2.js.json");
class LocalizedApp extends React.Component {
props: any;
static propTypes: { intl: (object: any, key: string, componentName: string, ...rest: any[]) => Error | null; };
render() {
return (...
<h1>{this.props.intl.formatMessage({ id: messages_ja.Cancel })}</h1>);}}
I get the following error:
[React Intl] An id must be provided to format a message.
Repeating my question:
Do I really need to incorporate the ecosystem for defining messages.
If so, why?
Is it possible to simply access the strings based on
locale from the json, without creating formattedMessages for them.
Thanks in advance.
Answer for question 1:
I'd say yes. You have to choose between using the declarative (e.g.: <FormattedMessage />) or the imperative api (e.g.: intl.formatMessage()).
Answer for question 2:
You could, but then why would you use react-intl then?
(You could say that you only want to use its localization methods for date, numbers, percentage.. which would be ok, but IMHO you'd have much more effort to build your own solution other than using the lib.)
I always prefer to use the declarative API, and it's a good practice to have an ID and a default message. This default message that react-intl complains is actually to help you. It's a fallback for in case you missed one translation, it defaults to this message.
I recommend using the imperative api if you want to reuse labels or if you need to use them outside react components (from my experience, these were the only cases where it could be done). You can also use the babel-plugin-react-intl to auto-extract the labels from your application and make your life pretty much easy!
I have a simple question.
I'm trying to append "tags" to an Elasticsearch array.
I find it hard to wrap my head around the scripting function in Elasticsearch, but found two queries that does the job, but both has to be called. Meaning that PHP (in my case), has to send two POST requests to the Elasticsearch database, which I think might cause some problems in the long term.
I think it would be safer to send it all in just one query.
The queries bellow is to update the votes of an array called tags from 1, to 2. I'm sure there are better ways of doing this than I have done.
Here are the queries I use:
I'm not sure why this votes: 2 are there, but it seems to do the job of deleting the tag. As I said, I find it hard to wrap my head around scripting in Elasticsearch.
POST /db2/links/1/_update
{
"script": {
"inline": "for(int i=0;i<ctx._source.tags.size();i++){if(ctx._source.tags[i].name==\"tagname\"){ctx._source.tags.remove(i)}}",
"params": {
"votes": 2
}
}
}
This query is for appending the tag to the tags array of the document
POST /db2/links/1/_update
{
"script": {
"inline": "ctx._source.tags.add(params.appendtags)",
"params": {
"appendtags": {
"name": "tagname",
"votes": 2
}
}
}
}
Are there any ways to easily combine these two scripts together in one query?
You can use bulk api to make multiple updates in a single call.
POST _bulk
{"update":{"_id":"1","_type":"links","_index":"db2","retry_on_conflict":3}}
{"script":{"inline":"for(int i=0;i<ctx._source.tags.size();i++){if(ctx._source.tags[i].name==\"tagname\"){ctx._source.tags.remove(i)}}","params":{"votes":2}}}
{"update":{"_id":"1","_type":"links","_index":"db2","retry_on_conflict":3}}
{"script":{"inline":"ctx._source.tags.add(params.appendtags)","params":{"appendtags":{"name":"tagname","votes":2}}}}
We are trying to use a custom analyzer (KeywordAnalyzer) using Azure Search Rest api-version: 2015-02-28-preview.
The Index definition code you see below is copied exactly from Microsoft docs.
This works if we put the Analyzer Type to CustomAnalyzer. However, if we make a single change by changing the analyzer type from CustomAnalyzer to any other analyzer such as KeywordAnalyzer, you get a Bad Request error when creating the Index and the Index is not created.
Would appreciate if anyone coud tell us how we can specify an Analyzer.
Many thanks
{
"name":"homes",
"fields":[
{
"name":"Id",
"type":"Edm.String",
"key":true,
"searchable":false},
{
"name":"IdStd",
"type":"Edm.String",
"searchable":true,
"analyzer":"my_analyzer"}
],
"analyzers":[
{
"name":"my_analyzer",
"#odata.type":"#Microsoft.Azure.Search.CustomAnalyzer",
"tokenizer":"my_standard_tokenizer",
"tokenFilters":[
"my_asciifolding",
"lowercase"
]
}
],
"tokenizers":[
{
"name":"my_standard_tokenizer",
"#odata.type":"#Microsoft.Azure.Search.StandardTokenizer",
"maxTokenLength":20}
],
"tokenFilters":[
{
"name":"my_asciifolding",
"#odata.type":"#Microsoft.Azure.Search.AsciiFoldingTokenFilter",
"preserveOriginal":true}
]
}
I'm from Azure Search. What's the error message you're seeing together with the BadRequest response code?
Edit:
I reread you question. Potentially you are specifying the tokenizer and tokenFilter properties for the KeywordAnalyzer. These properties only apply to the CustomAnalyzer. Please let me know if you find the documentation insufficient or confusing. We'll make sure to make it more clear and easier to follow.
I am using #RepositoryRestResource annotation to expose Spring JPA Data as restful service. It works great. However I am struggling with referencing specific entity within angular app.
As known, Spring Data Rest doesn't serialise #Id of the entity, but HAL response contains links to entities (_links.self, _embedded.projects[]._links.self) like in the following example:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/projects{?page,size,sort}",
"templated": true
}
},
"_embedded": {
"projects": [
{
"name": "Sample Project",
"description": "lorem ipsum",
"_links": {
"self": {
"href": "http://localhost:8080/api/projects/1f888ada-2c90-48bc-abbe-762d27842124"
}
}
},
...
My Angular application requires to put kind of reference to specific project entity in the URL, like http://localhost/angular-app/#/projects/{id}. I don't think using href is good idea. UUID (#Id) seems to be better but is not explicitly listed as a field. This is point I got stuck. After reading tons of articles I came up with 2 ideas, but I don't consider neither of those as a perfect one:
Idea 1:
Enable explicitly serialisation of #Id field and just use it to reference to the object.
Caveat: exposing database specific innards to front-end.
Idea 2:
Keep #Id field internal and create an extra "business identifier" field which can be used to identify specific object.
Caveat: Extra field in table (wasting space).
I would appreciate your comment on this. Maybe I am just unnecessarily too reserved to implement either of presented ideas, maybe there is a better one.
To give you another option, there is a special wrapper for Angular+Spring Data Rest that could probably help you out:
https://github.com/guylabs/angular-spring-data-rest