Should links in json-api responses be encoded? - rest

Should the query params in links appearing in JSON-API responses be percent-encoded?
The examples from jsonapi.org are not encoded, as in:
{
"links": {
"self": "http://example.com/articles",
"next": "http://example.com/articles?page[offset]=2",
"last": "http://example.com/articles?page[offset]=10"
},
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
}
]
}
However, there is also a note regarding encoding parameters in requests:
GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json
Note: The above example URI shows unencoded [ and ] characters simply for readability. In practice, these characters must be percent-encoded, per the requirements in RFC 3986.
Does this note apply only to requests? Or should responses also be percent-encoded, as in:
{
"links": {
"self": "http://example.com/articles",
"next": "http://example.com/articles?page%5Boffset%5D=2",
"last": "http://example.com/articles?page%5Boffset%5D=10"
},
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
}
]
}

Yes, the note about encoding URI's in your question applies only to the request, not the response
With a json string returned inside a response, the only thing required to escape is the double quote character "
GET requests (not responses) are a different ball of wax. Anything in a GET request passed as a parameter in the URL must be URL encoded. So if you have a parameter url=http://some.url.com, the url on the right of the parameter assignment needs encoding.
It's tricky with POST and PUT requests. Depending on the content type set in the header you may need to encode. If your content type is application/json, you should not need to url encode anyting in your json string, (excluding the before mentioned ").
Now, if the specificed content encoding you state doesn't match what your sending (or if you didn't explicitly add one and it defaults to something), like if you send content-type: application/x-www-form-urlencoded but send a json string, the API service may or may not accept it and who know what how it will treat the content inside as far a url decoding it.

Related

Response tag with URL parameter

Is there any way in an Insomnia request to use the response body of a sub-request in the request body, and at the same time specify a URL parameter for that sub-request?
Consider an API with endpoints like these:
[GET] _.base_url/customers/{id}
[GET] _.base_url/products/{id}
[POST] _.base_url/invoices
When POSTing to the invoices endpoint, the API expects a JSON body along these lines (highly simplified, of course):
{
"date": "2022-03-31",
"currency": "USD",
"customer": {
"id": 123,
"name": "Something Corp.",
"address": "Here, there and everywhere"
},
"items": [
{
"id": 456,
"description": "Thingamajig",
"price": 11500
},
{
"id": 789,
"description": "Doodad",
"price": 23900
}
]
}
That is, it expects the customer field and each of the items fields to be full objects, not just IDs. (And yes, that’s stupid and not RESTful, but I don’t control the API.)
The proper way to retrieve such objects would obviously be to call the two GET endpoints with the IDs as part of the URL, and then using the responses as response tags in the POST request – but I cannot find a way to do this.
There’s a lengthy GitHub discussion on per-request veriables which has so far not produced any results, but even the suggested PR in that thread doesn’t seem like it would support defining the URL parameters when calling the request, rather than in the request itself.
Is there some way to achieve this in Insomnia?

JSON LD serialization from schema.org

The following example is given on the json-ld playground.
Person example(expanded):
json-ld:
{
"#context": "http://schema.org/",
"#type": "Person",
"name": "Jane Doe",
"jobTitle": "Professor",
"telephone": "(425) 123-4567",
"url": "http://www.janedoe.com"
}
after serializtion to expanded:
[
{
"#type": [
"http://schema.org/Person"
],
"http://schema.org/jobTitle": [
{
"#value": "Professor"
}
],
"http://schema.org/name": [
{
"#value": "Jane Doe"
}
],
"http://schema.org/telephone": [
{
"#value": "(425) 123-4567"
}
],
"http://schema.org/url": [
{
"#id": "http://www.janedoe.com"
}
]
}
]
I ask myself where does the serializer gets the information to map the properties to the right subsequent schema (name). To achieve that, it must be able to get hold on to the person json ld schema. But if I go to https://schema.org/Person I get an HTML back and not a JSON-LD file.
So where does the serialization knowledge come from?
Jay is correct that the knowledge comes from the #context. This can be specified in a couple of ways:
Inline, using an object value for #context (or an array, which includes an object),
By directly retrieving a context from the URL specified (e.g., https://json-ld.org/contexts/person.jsonld),
By having the server do context-negotiation on the request, as an HTTP request includes an Accept header preferring JSON-LD (see Interpreting JSON as JSON-LD) such as the following:
GET /ordinary-json-document.json HTTP/1.1
Host: example.com
Accept: application/ld+json,application/json,*/*;q=0.1
Or, as is presently deployed by schema.org, by returning a Link header along with a GET or HEAD request identifying the location of the actual context to load (See Alternate Document Location):
HTTP/1.1 200 OK
...
Content-Type: text/html
Link: <alternate.jsonld>; rel="alternate"; type="application/ld+json"
This last case is used by schema.org because of the challenges of making HTTP Content-Negotiation work properly on certain static site generators. If you to a HEAD request at https://schema.org, you'll get back headers including the following:
HTTP/2 200
link: </docs/jsonldcontext.jsonld>; rel="alternate"; type="application/ld+json"
A conforming JSON-LD processor (such as on the json-ld.org playground) knows to follow this link to find the actual context.
In the case of the Person example, "Person" and the other keys are turned into IRIs based on instructions in that context file such as the following:
{
"#context": {
...
"schema": "http://schema.org/",
"Person": {"#id": "schema:Person"},
"name": { "#id": "schema:name"},
"jobTitle": { "#id": "schema:jobTitle"},
"telephone": { "#id": "schema:telephone"},
"url": { "#id": "schema:url", "#type": "#id"},
...
}
}
Note that in the case of "url", it also knows that the value of that property should be treated as an IRI, rather than a text string.

How to pass a very long array of objects within a query string?

There is a RESTful API with some resource. I need to GET some resource with parameter which in JSON representation looks like:
{
"id": int,
"params":
[
{
"param1": "string",
"param2": "string"
},
{
"param1": "string",
"param2": "string"
}
]
}
I have two possible ways to send this object in the query string:
id=1&params[0].param1=test&params[0].param2=test&params[1].param1=test&params[1].param2=test
id=10000&params[0][param1]=test&params[0][param2]=test&params[1][param1]=test&params[1][param2]=test
The problem is that params array can have a lot of items and the query string can be very long, over 2,000 characters.
To send params in the request body via GET is bad idea.
How I can send such params in a proper RESTful way? Can I use other HTTP method? Or just change the query length on the server?
Use a POST method to get some data because params are too long for a GET method ISN'T a bad idea.
You can add the search options in body of request in JSON like
{
"id": int,
"params":
[
{
"param1": "string",
"param2": "string"
},
{
"param1": "string",
"param2": "string"
}
]
}
If you want an idempotent request URI (i.e. response is always the same), then use GET, else POST.
For more details you can find here for answers:- Why should I POST data rather than GET?

SugarCRM API - Filter POST - Related Module Fields

I'm trying to retrieve, using REST API, a list of records and one of its related module fields. Let's assume Accounts and Opportunities.
So, API Documentation (in the GET Filter) talks about defining related module in the fields parameter:
According to the same documentation, it would provide a result similiar to:
That's exactly what I need, but I'm trying to achieve this using the POST method. So, following the same path, I'm sending (using Postman):
PS: I tried all combinations of double quotes. Escaped, not escaped, with or without it, all of them give me the same result, that is:
The message is in pt-BR but it means "One of your request parameters is wrong". The HTTP status code is 422 - Unprocessable Entity.
What am I doing wrong? I tried everything and just don't know how to make it work. Looks like the documentation talks about something that simply don't work or doesn't exist.
Okay, so after some research, it seems that Postman uses something similar to Chrome and it isn't really possible to send GET requests with the values in the body. However, you can...
Encode the values into the URL and send it through Postman:
https://yoursite.com/rest/v10/Accounts?filter%5B0%5D%5Bopportunities.date_modified%5D%5B%24gte%5D%3D2016-02-29T00%3A00%3A00&fields=cpf_c,opportunities&max_num=10
Use curl:
curl -X GET -H Host:yoursite.com -H OAuth-Token:d49c8fd4-0ae0-d9fb-7ab8-5846e5a3fa86 -H Cache-Control:no-cache -d '{"filter":[{"opportunities.date_modified":{"$gte":"2016-02-29T00:00:00"}}],"fields":["cpf_c","opportunities"],"max_num":"10"}' https://yoursite.com/rest/v10/Accounts
Or build the HTTP request directly, and include the body:
GET https://yoursite.com/rest/v10/Accounts HTTP/1.1
Host: yoursite.com
OAuth-Token:d49c8fd4-0ae0-d9fb-7ab8-5846e5a3fa86
Cache-Control:no-cache
{"filter":[{"opportunities.date_modified":{"$gte":"2016-02-29T00:00:00"}}],"fields":["cpf_c","opportunities"],"max_num":"10"}
To test this, I created 3 Accounts, 2 of which had an Opportunity linked. The response was this when I used "name" instead of your "cpf_c" field:
{
"next_offset": -1,
"records": [{
"id": "64417139-459c-852f-3a73-5846ed1245c2",
"name": "another account with opp",
"date_modified": "2016-12-06T16:54:29+00:00",
"opportunities": {
"next_offset": -1,
"records": [{
"id": "32d1d320-c560-92d6-7def-5846eda786da",
"date_modified": "2016-12-06T16:55:06+00:00",
"_acl": {
"fields": {}
},
"_module": "Opportunities"
}]
},
"_acl": {
"fields": {}
},
"_module": "Accounts"
}, {
"id": "48dc47dd-bbf1-816d-b0ac-5846e6dd9e21",
"name": "test with opp",
"date_modified": "2016-12-06T16:23:33+00:00",
"opportunities": {
"next_offset": -1,
"records": [{
"id": "79c3bf6f-6c2b-7945-09f7-5846e6c610d7",
"date_modified": "2016-12-06T16:24:20+00:00",
"_acl": {
"fields": {}
},
"_module": "Opportunities"
}]
},
"_acl": {
"fields": {}
},
"_module": "Accounts"
}]
}
Hope this helps.

Decrypting the payload in hyperledger

I am currently using Developer Environment for Hyperledger Fabrics. I tried using GET to retrieve block info and it does give me a response. However, in the response, there's one component called payload, and it's in a unreadable format. Is there a way to make it readable/decrypt it? For instance, in bluemix, when you do init of party "a" and party "b", the payload shows inita100b100.
Firstly, I did this transaction/REST request
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID":{
"name":"mycc"
},
"ctorMsg": {
"function":"invoke",
"args":["a", "b", "100"]
}
},
"id": 3
}
Then I did this query request
GET/localhost:5000/transactions/c6b0c82d-27f9-4c2c-8305-34b413d95057
and got back this as REST response
{
"type": 2,
"chaincodeID": "EgRteWNj",
"payload": "Ch8IARIGEgRteWNjGhMKBmludm9rZRIBYRIBYhIDMTAw",
"uuid": "c6b0c82d-27f9-4c2c-8305-34b413d95057",
"timestamp": {
"seconds": 1469643763,
"nanos": 524731069
}
}
So if there's anyway to decrypt/change Ch8IARIGEgRteWNjGhMKBmludm9rZRIBYRIBYhIDMTAw to showing A transferred 100 to b or something similar, at least being readable for less-technical users?
The payload is just encoded, you can use this to decode it (the encoding is base64). There is also this function in javascript to decode it.
If you had security/privacy enabled, the payload would be encrypted too, so you would need the Certificate to decrypt the payload and then you could decode it.