REST API PATCH - update a specific value in an object - rest

In a config file, I've got several vars.
{
"key1": "aaa",
"key2": {"smallkey1": "bbb", "smallkey2": "ccc"}
}
I need to update smallkey2 value, through a patch request (API obligation).
const updateConfigVar = (finaltarget, newdata) => {
HTTP.call( 'PATCH', 'https://api.xxx.com/apps/', {
headers: {
"Content-Type": "application/json"
},
data: {
[finaltarget]: newdata,
}
})
}
If I call updateConfigVar('key2', 'ddd'), I get:
{
"key1": "aaa",
"key2": "ddd"
}
But how to replace not the all key2 object but only the value of smallkey2 inside the key2 object.
So how to get:
{
"key1": "aaa",
"key2": {"smallkey1": "bbb", "smallkey2": "ddd"}
}

But how to replace not the all key2 object but only the value of smallkey2 inside the key2 object.
Normally, if we are using HTTP Patch to communicate a change to the server
The set of changes is represented in a format called a "patch document" identified by a media type.
You probably don't want to be using application/json as your media type, because the processing rules for JSON aren't specific to patching. A better bet would be to use either application/json-patch+json (described by RFC 6902) or application/merge-patch+json (described by RFC 7386).
Each of these has their own specific semantics for describing an edit to a nested key.

Related

Akka HTTP, Spray Json and Option Fields Failing as Required

I have a case class:
case class OpcTagPlaybook(name: String, tags: Seq[OpcTagAtTime], looped: Boolean, enabled: Option[String])
With an optional enabled field that will contain a date.
Spray Json describes encoding/decoding:
implicit val opcTagPlaybookFormat = jsonFormat4(OpcTagPlaybook)
And a route in akka http:
post {
entity(as[OpcTagPlaybook]) { playbook =>
val playbookCreated: Future[_] =
(opcTagPlaybookActor ? UpsertPlaybook(playbook))
onSuccess(playbookCreated) { _ =>
log.info("Created playbook [{}]", playbook.name)
complete((StatusCodes.Created, "ok"))
}
}
})
For some reason posting without the createdAt field fails:
Posting:
{"name": "test1",
"tags":[{"offset": 100, "tag": "hello", "value": "yo"}],
"looped": true
}
Fails:
The request content was malformed:
Object is missing required member 'enabled'
And if I post created it gives me another error:
{"name": "test1",
"tags":[{"offset": 100, "tag": "hello", "value": "yo"}],
"looped": true,
"enabled": "2018-08-08"
}
gives
The request content was malformed:
spray.json.JsString cannot be cast to scala.Option
I'm assuming this is some interplay between akka http and so I'm going to just deal with the input more manually but I'd just like to understand what I'm doing wrong here.

How to perform PATCH operation in Firebase APi?

The firebase doc sys this is how it is supposed to be done:
curl -X PATCH -d '{"last":"Jones"}' \
'https://[PROJECT_ID].firebaseio.com/users/jack/name/.json'
But I dont know how to convert this to a rest based request.
TO be clear I need to send a web request from javascript/java, hence I want to know what should be the body , and header and operation type for this request.
Can someone please help?
If you use the documentation for curl, you can figure out what that command line you showed is trying to tell you.
The HTTP method is: PATCH
The request body is: {"last":"Jones"}
The url is: https://[PROJECT_ID].firebaseio.com/users/jack/name/.json
Where PROJECT_ID is the name of your project. That's all there is to it.
You need teh following structure:
HTTP Request:
https://firestore.googleapis.com/v1/projects/*YOUPROJECT_ID*/databases/(default)/documents/users_admin/*DOCUMENT_ID*?**updateMask.fieldPaths=user_name&updateMask.fieldPaths=permisos.Administrador&updateMask.fieldPaths=user_email**
JSON Body (must be exactly the same structure and type as your database):
{
"fields": {
"user_name": { "stringValue": "Test ActualizaciĆ³n 2" },
"permisos": {
"mapValue": {
"fields": {
"Administrador": {
"booleanValue": true
}
}
}
},
"user_email": { "stringValue": "veviboj548#eyeremind.com" }
}
}

Adding a key/value pair to an object in VTL (for API Gateway)

I am writing a mapping template for an AWS API Gateway integration response. I would like to add a key/value pair to the JSON object returned my Lambda function.
My function returns some JSON like this:
{
"id": "1234",
"name": "Foo Barstein"
}
I would like the template to output something like this:
{
"id": "1234",
"name": "Foo Barstein",
"href": "https://example.tld/thingy/1234"
}
And my mapping template looks like this:
#set($thingy = $input.json('$'))
#set($thingy.href = "https://example.tld/thingy/$thingy.id")
$thingy
However, my template outputs the unmodified $thingy, without the href I have tried to add.
I've read the VTL user guide, but to no avail.
Something like this has worked for me:
#set($body = $input.path('$'))
#set($body.href = "https://example.tld/thingy/$body.id")
$input.json('$')
There is no easy way to achieve this but you can workaround it:
## Mapping template
#set($body = $input.body)
#set($id = $input.json('$.id'))
{
"custom": {
"href" : "https://example.tld/thingy/$id"
},
"body": $body
}
And then merge all the keys in AWS.Lambda (if you use Lambda):
## Lambda handler
exports.handler = function(event, context) {
const requestParams = Object.assign({}, event.body, event.custom);
// ... function code
}
And requestParams will be what you want.
Following could do the trick. Beware, untested!
{
#set($payload = $util.parseJson($input.json('$')))
#set($body = "{
#foreach ($mapEntry in $payload.entrySet())
""$mapEntry.key"": ""$mapEntry.value"",
#end
""href"": ""$payload.id""
}")
$body
}

"Resource Not Found" message received when sending a query to Keen IO API

I am using Advanced REST Client tool to test a data pull from the Keen IO API, and think getting the request right, but not getting the data. Getting "resource not found" error. This can also be done via CURL.
Headers: Authorization:
Content-Type: application/json
actual request: GET /3.0/projects//queries/saved/Sponsorships/result HTTP/1.1
HOST: api.keen.io
authorization:
content-type: application/json
Base URL used: https://api.keen.io
Any ideas as to what may be doing wrong?
The saved query name is capitalized "Sponsorships". Make sure your saved query name is lower-cased, not camel or title-cased. To be sure that you are getting the correct saved query name.
Also, you may want to first obtain a list of all saved queries as a reference:
GET /3.0/projects/<project_name>/queries/saved HTTP/1.1
HOST: api.keen.io
authorization: <your_key>
content-type: application/json
You will get something like this:
[
{
"refresh_rate": 0,
"last_modified_date": "2016-12-20T01:09:54.355000+00:00",
"query_name": "",
"created_date": "2016-12-20T01:09:54.355000+00:00",
"query": {
"filters": [],
"latest": 100,
"analysis_type": "extraction",
"timezone": "UTC",
"timeframe": "this_30_days",
"event_collection": ""
},
"metadata": {
"visualization": {
"chart_type": "table"
},
"display_name": ""
},
"run_information": null
}
]
FWIW, I also have seen the "Resource not found" error when writing data to an event if the project is not correctly set up. For example, passing in the wrong project_id or write_key or if the project was deleted from your Keen.io account.

Different authorization header for each operation in a Guzzle client service description

The API I'm accessing requires a custom authorization header that is a combination of the publicKey that is passed in when the client is instantiated and the complete URI of the API endpoint. I want to pull the baseUrl and operation uri out of the service description and use them to create the authorization header, but I can't figure out how to do this when calling the instantiated client.
This is the service description:
{
"name": "FranchiseSystem",
"apiVersion": "1",
"baseUrl": "https://apidev.example.com",
"description": "REST API client",
"operations": {
"GetFranchiseList": {
"httpMethod": "GET",
"uri": "v1/franchise",
"summary": "Returns an array of franchises."
},
"GetReviews": {
"httpMethod": "GET",
"uri": "v1/review",
"summary": "Returns an array of reviews."
}
}
}
This is the client setup:
$testClient = new JunknetClient([
'publicKey' => '1234567890',
]);
This is the call to the instantiated client with the name of the operation:
$result = $testClient->GetFranchiseList();
or:
$result = $testClient->GetReviews();
When testClient->GetFranchiseList is called, I need to create the authorization header using the publicKey and the values of baseUrl and uri for GetFranchiseList.
When testClient->GetReviews is called, I need to create the authorization header using the publicKey and the values of baseUrl and uri for GetReviews.
You might want to have a look at the following links from the Guzzle docs.
Request Options - Headers
Authentication Parameters
I was able to solve my problem by using and event emitter and subscriber. It's a bit messy, but it get's the job done.
private function handleCredentialsOptions(Collection $config) {
//Build authorization header from $config values
$this->getHttpClient()->getEmitter()->on('before',
function (BeforeEvent $e) use(&$config) {
$this->getHttpClient()->setDefaultOption('headers', [
'Authentication' => '',
]);
$path = $e->getRequest()->getUrl();
$authValue = $config['publicKey'].';;';
$authValue .= time().';';
$authValue .= strtoupper(md5($config['privateKey'] . $path));
$this->getHttpClient()->setDefaultOption('headers', [
'Authentication' => $authValue,
]);
});
}