How to get PubSub message data in an API? - google-cloud-pubsub

I want to get this kind of message json data from Pub/Sub
{
"message": {
"data": {
"from": "no-reply#example.com",
"to": "user#example.com",
"subject": "test",
"body": "test"
}
}
}
And parse its data to use for other service.
private parseMessage(message: Message) {
try {
const decoded = Buffer.from(message.data.toString(), 'base64').toString().trim();
return JSON.parse(decoded);
} catch (err) {
throw new BadRequestException(
'Parse Error: ' + message,
);
}
}
But when run the API got this error:
SyntaxError: Unexpected token � in JSON at position 0
at JSON.parse (<anonymous>)
at EventController.parseMessage (../myapp/src/api/posts/posts.controller.ts:44:18)
response: {
statusCode: 400,
message: 'Parse Error: [object Object]',
error: 'Bad Request'
},
status: 400
It seems this post isn't right:
curl -X 'POST' \
'http://localhost:3000/posts' \
-H 'Content-Type: application/json' \
-d '{
"message": {
"data": {
"from": "no-reply#example.com",
"to": "user#example.com",
"subject": "test",
"body": "test"
}
}
}'
Then how to make fake Pub/Sub message data?

I think you need to encode your data into Base64.
Base64 encoding schemes need to encode binary data that needs to be stored and transferred over media that are designed to deal with ASCII. This is to ensure that the data remain intact without modification during transport.
You can also refer to this GCP public documentation.
Eg. From the Doc:
# 'world' base64-encoded is 'd29ybGQ='
curl localhost:8080 \
-X POST \
-H "Content-Type: application/json" \
-d '{
"context": {
"eventId":"1144231683168617",
"timestamp":"2020-05-06T07:33:34.556Z",
"eventType":"google.pubsub.topic.publish",
"resource":{
"service":"pubsub.googleapis.com",
"name":"projects/sample-project/topics/gcf-test",
"type":"type.googleapis.com/google.pubsub.v1.PubsubMessage"
}
},
"data": {
"#type": "type.googleapis.com/google.pubsub.v1.PubsubMessage",
"attributes": {
"attr1":"attr1-value"
},
"data": "d29ybGQ="
}
}'

Related

Query tensor in vespa.ai

Imitating: https://blog.vespa.ai/billion-scale-knn/
Command line:
curl -s -d '{"yql":"select * from user where {\"targetHits\":10}nearestNeighbor(approximate, q_binary_code);","ranking.features.query(q_binary_code)":[1,2,3,4,5,6,7,8,9,10],"hits":10}' -H "Content-Type: application/json" -X POST http://localhost:8080/search/ | jq .
Error message:
{
"root": {
"id": "toplevel",
"relevance": 1,
"fields": {
"totalCount": 0
},
"errors": [
{
"code": 4,
"summary": "Invalid query parameter",
"source": "content",
"message": "Expected a tensor value of 'query(q_binary_code)' but has [1,2,3,4,5,6,7,8,9,10]"
}
]
}
}
Question: How pass q_binary_code?
With recent Vespa versions, you can define the query tensor in the schema. It must be defined
schema code {
document code {
field id type int {..}
field binary_code type tensor<int8>(b[16]) {..}
}
rank-profile coarse-ranking {
inputs {
query(q_binary_code) tensor<int8>(b[16])
}
num-threads-per-search:12
first-phase { expression { closeness(field,binary_code) } }
}
You also must define the rank profile in the query request:
curl -s -d '{"yql":"select * from user where {\"targetHits\":10}nearestNeighbor(binary_code, q_binary_code);","ranking.features.query(q_binary_code)":[1,2,3,4,5,6,7,8,9,10],"hits":10, "ranking": "coarse-ranking"}' -H "Content-Type: application/json" -X POST http://localhost:8080/search/ | jq .

curl post array data

My JSON Block
{
"type": "abcd",
"data": {
"id": [
"efgh"
],
"model": "ijkl"
}
I tried updating 'type' using the following curl post, but it doesn't like it.
curl -X PUT -d '{"id":["ABCD"]}'

equiv: "Could not add an item of type WORD_ALTERNATIVES"

Using equiv() on an empty table throws a strange error in vespa.ai 7.99.22:
Could not add an item of type WORD_ALTERNATIVES: Equiv can only have word/int/phrase as children
Definition:
search post {
document post {
field description type string {
indexing: summary | index
stemming: multiple
}
}
fieldset text {
fields: description
}
}
Query (no rows in table post):
curl -s -H "Content-Type: application/json"
--data '{"yql" : "select * from post where text contains equiv(\"Q123\",\"Q456\");"}'
http://localhost:8080/search/ | jq .
Result:
{
"root": {
"id": "toplevel",
"relevance": 1,
"fields": {
"totalCount": 0
},
"errors": [
{
"code": 4,
"summary": "Invalid query parameter",
"source": "content",
"message": "Could not add an item of type WORD_ALTERNATIVES: Equiv can only have word/int/phrase as children"
}
]
}
}
What is the issue?
Using stemming:multiple leads to a WordAlternativesItem which is not a permitted child of EquivItem, so this combination is not supported.
However, we believe this is unnecessarily restrictive. I'ill lift this restriction now, please try again in the next version which should be out on Monday (2019-09-16) if the winds are favourable.

swagger-js-codegen api is sending the wrong request header content-type

So I have newly upgraded to Swagger 2 from 1.x, and am experiencing an odd issue. One of my APIs is getting an incorrect content-type injected into the header and I have no idea where from, you can see below in the SwaggerJSON, The DELETE function even says it consumes application/json, but the CURL(copied from inspect panel) for it sends 'Content-Type: text/plain;charset=UTF-8'. I have provided the CREATE function as a cursory example to show that otherwise the similar apis work fine. I think this is an issue with swagger-js-codegen because if I put the same request into the api-docs it works fine, or of course my Java, or somewhere somehow my content-type header is getting set, but i have no idea how or where. Am I missing something? The API acts the same whether or not my JAVA claims 'consume = "application/json"' or not.
Swagger JSON
{
"/api/entities/{id}/labels": {
"delete": {
"consumes": [
"application/json"
],
"operationId": "deleteEntityLabel",
"parameters": [
{
"default": "16_appiniteDev",
"description": "The id of the entity to be edited",
"in": "path",
"name": "id",
"required": true,
"type": "string"
},
{
"description": "The label/labels to be deleted",
"in": "body",
"name": "labels",
"required": true,
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/ResponseEntity"
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
},
"summary": "Deletes Labels for Entities",
"tags": [
"entity-resource"
]
},
"post": {
"consumes": [
"application/json"
],
"operationId": "createEntityLabel",
"parameters": [
{
"default": "16_appiniteDev",
"description": "The id of the entity to be edited",
"in": "path",
"name": "id",
"required": true,
"type": "string"
},
{
"description": "The array of labels to be set",
"in": "body",
"name": "labels",
"required": true,
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/ResponseEntity"
}
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
},
"summary": "Creates Labels for Entities",
"tags": [
"entity-resource"
]
}
}
}
DELETE
JAVA/SPRING
/**
* DELETE /entities/{id}/labels -> delete labels for an entity
*
* #param id
* #param labels
* #throws ServiceException
*/
#RequestMapping(value = "/entities/{id}/labels", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#ApiOperation(value = "Deletes Labels for Entities", nickname = "deleteEntityLabel", consumes = "application/json")
public ResponseEntity deleteLabels(
#ApiParam(value = "The id of the entity to be edited", required = true, defaultValue = "16_appiniteDev") #PathVariable final String id,
#ApiParam(value = "The label/labels to be deleted", required = true, defaultValue = "[\"label1\",\"label2\",\"label3\"]") #NotNull final #RequestBody String[] labels
) throws ServiceException {
boolean isAppEntity = false;
User user = userService.getUserWithAuthorities();
String[] type = id.split("_");
if (StringUtils.isNumeric(type[0]) && !type[1].startsWith(type[0])) {
isAppEntity = true;
}
entityService.deleteTags(id, labels, user, isAppEntity);
Map<String, String> response = new LinkedHashMap<>();
response.put(Constants.RESPONSE_ENTITY_HEADER_MESSAGE,
"Labels deleted successfully");
return new ResponseEntity(response, HttpStatus.OK);
}
CURL FROM APP
curl 'http://localhost:8080//api/entities/52_QA42/labels?cacheBuster=1472070679337' -X DELETE -H 'Pragma: no-cache' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' -H 'Content-Type: text/plain;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'x-auth-token: admin:1472097365429:8e6524e252e2aebb786b7738c44fe385' -H 'Referer: http://localhost:8080/' -H 'Cookie: NG_TRANSLATE_LANG_KEY=%22en%22' -H 'Connection: keep-alive' -H 'DNT: 1' --data-binary '["Bug13124"]' --compressed
CREATE
JAVA/SPRING
/**
* POST /entities/{id}/labels -> add labels for a non hadoop entity
*
* #param id
* #param labels
* #throws ServiceException
*/
#RequestMapping(value = "/entities/{id}/labels", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#ApiOperation(value = "Creates Labels for Entities", nickname = "createEntityLabel")
public ResponseEntity addLabels(
#ApiParam(value = "The id of the entity to be edited", required = true, defaultValue = "16_appiniteDev") #PathVariable final String id,
#ApiParam(value = "The array of labels to be set", required = true, defaultValue = "[\"label1\",\"label2\",\"label3\"]") #NotNull final #RequestBody String[] labels)
throws ServiceException {
boolean isAppEntity = false;
User user = userService.getUserWithAuthorities();
String[] type = id.split("_");
if (StringUtils.isNumeric(type[0]) && !type[1].startsWith(type[0])) {
isAppEntity = true;
}
entityService.addTags(id, labels, user, isAppEntity);
Map<String, String> response = new LinkedHashMap<>();
response.put(Constants.RESPONSE_ENTITY_HEADER_MESSAGE,
"Labels added successfully");
return new ResponseEntity(response, HttpStatus.OK);
}
CURL FROM APP
curl 'http://localhost:8080//api/entities/52_QA42/labels?cacheBuster=1472071851544' -H 'Pragma: no-cache' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'x-auth-token: admin:1472097365429:8e6524e252e2aebb786b7738c44fe385' -H 'Referer: http://localhost:8080/' -H 'Cookie: NG_TRANSLATE_LANG_KEY=%22en%22' -H 'Connection: keep-alive' -H 'DNT: 1' --data-binary '["test"]' --compressed
Any Ideas?
I haven't been able to nail down how or where it is setting that Content-Type, so I've fixed this in a brute force way: Created an interceptor to change the header content-type by force:
.factory('contentInterceptor', function ($rootScope, $q, $location, localStorageService, $cookies) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
config.headers['Content-Type'] = 'application/json';
return config;
}
};
})
.config(function ($httpProvider) {
$httpProvider.interceptors.push('contentInterceptor');
});
Works like a charm, and luckily doesn't affect any other of my API's as they ALL require Application/JSON except for the multipart form ones, but those explicitly get set and aren't affected by this interceptor.
**** UPDATE *****
I'm a dumb dumb and didn't realize I could've just put the following in my mustache template. This is the correct answer. It takes the proper 'consumes' and 'produces' properties and ensures the right headers are being sent.
{{#headers}}
options.headers['{{&name}}'] = {{&value}};
{{/headers}}

How do I transform this Paypal curl request into an ajax or angular request?

I have a Paypal request done in curl. However, I want to use AngularJS to send this request. How do I rewrite this request in AngularJS ? Or could I just use curl inside my AngularJS request ? If so, how ?
curl -v https://api.sandbox.paypal.com/v1/payments/payouts?sync_mode=true \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <Access-Token>" \
-d "{
"sender_batch_header": {
"email_subject": "You have a payment"
},
"items": [
{
"recipient_type": "EMAIL",
"amount": {
"value": 12.34,
"currency": "USD"
},
"receiver": "shirt-supplier-one#mail.com",
"note": "Payment for recent T-Shirt delivery",
"sender_item_id": "A123"
}
]
}"
Here is the link to my jsfiddle.net/dv9v4t61/4

Resources