Return json string grpc proto3 - grpc

How to write proto3 syntax with which proper json string is returned ?
message Response{
string jsonString = 1;
}
rpc getSomeThing() { returns (Response) }
Actual Response :
{ "subject": "dev", "body":
"{"name":"environment","description":"The default
environment"}", }
Expected Response:
{ "subject": "dev", "body":
{"name":"environment","description":"The default environment"}, }

Related

Common generic class to handle server response in flutter

I'm calling requesting server for data and getting following response.
{
"success": 1,
"data": [
{
"id": 1,
"name": "Kurti"
},
{
"id": 2,
"name": "Top"
}
],
"message": "Data fetched"
}
Modal class to convert json data coming from server.
class Product {
String categoryName;
int productId;
Product.fromJson(Map<String, dynamic> json) {
categoryName = json["id"];
productId = json["name"];
}
}
So from the server the format will be fix for every call like below...
{
"success": <Int>,
"message": <String>,
"data": <An array of Model class>
}
For that I've created below class...
class ServerResponse<T> {
String message;
int success;
List<T> data;
ServerResponse.fromJson(Map<String, dynamic> json) {
message = json["message"];
success = json["success"];
data = json["product_data"];
}
}
And this is how I'm calling api...
class ServerManager {
final baseUrl = isProduction ? liveServer : stagingServer;
var headers = {"consumer-key": "sdfgdqwrtw34563t545"};
dynamic callWSToGetData({Map<String, String> params}) async {
var client = http.Client();
var url = baseUrl + allProducts;
print("URL = $url");
print("params: $params");
print("header: $headers");
var response = await client.post(url, headers: headers, body: params);
var json = converter.jsonDecode(response.body);
return json;
}
}
Calling api to get data as following.
Map<String, String> params = {"categories_id": "1", "language_id": "1", "type": "Newest", "customers_id": "0", "page_number": "0"};
var response = ServerManager().callWSToGetData(params: params);
var res = ServerResponse<Product>.fromJson(response);
print(res.data);
So when I ran this code I'm getting following error.
type 'Future' is not a subtype of type 'Map'
The question is...
How can I create a single generic class that can be used to handle server responses?
Any help please.
type 'Future' is not a subtype of type 'Map'
This is probably due to missing await call. Your callWSToGetData has async in declaration so it's type will be Future.
To use generics you need to pass the type. So your code will look like this:
var response = await ServerManager().callWSToGetData(); //how can I use generic here
var res = ServerResponse<Product>.fromJson(response);
print(res.data);

How to send a POST request to Firebase Cloud Messaging API in Vapor

I am trying to make a POST request to a Firebase Notifications API using Vapor 1.5 and Firebase Legacy Protocol, but I get failure response.
response is JSON(node: Node.Node.object(["multicast_id":
Node.Node.number(5936281277445399934), "failure": Node.Node.number(0),
"canonical_ids": Node.Node.number(0), "results":
Node.Node.array([Node.Node.object(["message_id":
Node.Node.string("0:1527074314969790%c7ade8b9f9fd7ecd")])]),
"success": Node.Node.number(1)]))
EDIT
Making the request through POSTMan fails with error "The request was missing an Authentication Key (FCM Token)."
class FirebaseRequester {
let fcmLegacyServerKey = "AIzaSyDSuXXXXXXkCafTQay5_r8j3snvVos"
func sendNotification(payLoad: JSON) throws -> Response {
var response: Response?
do {
let responseFCM = try drop.client.post("https://fcm.googleapis.com/fcm/send",
headers: ["Content-Type":"application/json","Authorization": "key\(fcmLegacyServerKey)"],
query: [:],
body: payLoad.makeBody())
response = responseFCM
}catch let error {
let message = error.localizedDescription
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
guard let rsp = response?.json else {
let message = "no json received on line \(#line)"
drop.log.error(message)
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
print("rsp in json format is \(rsp)")
return response!
}//end of sendNotification()
}//end of class FirebaseRequester
//make another class here and initialize it with FirebaseRequester
//get data from Client App
// validate data
// finally, create the payLoad and call sendNotification(:)
//request should look like
{
"aps": {
"alert": "Breaking News!",
"sound": "default",
"link_url": "https://raywenderlich.com"
}
}
let fcmKeyToSendTo = "someDeviceTokenKeyReceivedFromClient_biHZNI-e9E53WEkCzrki"
let data = try Node(node: ["alert": "alert", "sound": "sound", "link_url": "https://www.someWebsite.com"])
var payLoadObj = try JSON(node: ["aps" : data])
payLoadObj["to"] = try JSON(node: fcmKeyToSendTo)
do {
let _ = try firebaseRequester.sendNotification(payLoad: payLoadObj)
}catch{
logErr.prints(message: error.localizedDescription)
}
let message = "notification Sent"
return try JSON(node:["success":message])
In sendNotification(payload:) I had a typo, I missed = after key. It should have been "key=\(fcmLegacyServerKey)"
In sendNotification(payload:), payLoad.makeBody should not be called, I should have just passed the JSON object payLoad as an argument to the .post request.
The JSON object of the notification was clearly badly formatted from the outset. The message type I wanted to send was notification, but I was passing in a key named aps. I should have passed key notification as shown below.
.
class FirebaseRequester {
let fcmLegacyServerKey = "AIzaSy....vVos"
func sendNotification(payLoad: JSON) throws -> Response {
var response: Response?
do {
let responseFCM = try drop.client.post("https://fcm.googleapis.com/fcm/send",
headers: ["Content-Type":"application/json","Authorization": "key=\(fcmLegacyServerKey)"],
query: [:],
body: payLoad
response = responseFCM
}catch let error {
let message = error.localizedDescription
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
guard let rsp = response?.json else {
let message = "no json received on line \(#line)"
drop.log.error(message)
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
return response!
}//end of sendNotification()
}//end of class FirebaseRequester
class TestRouteNow {
let firebaseRequester: FirebaseRequester
init(firebaseRequester: FirebaseRequester) {
self.firebaseRequester = firebaseRequester
}
func addRoutes(drop: Droplet) {
drop.post("test", "notif", handler: postNotification)
}
func postNotification(request: Request) throws -> ResponseRepresentable {
let fcmDevice = "someDeviceTokenReceivedFromClientApp"
let data = try Node(node: ["title": "title","body": "body", "sound": "default", "badge":"60"])
var payLoadObj = try JSON(node: ["notification": data])
payLoadObj["to"] = try JSON(node: fcmDevice)
do {
let _ = try firebaseRequester.sendNotification(payLoad: payLoadObj)
}catch{
logErr.prints(message: error.localizedDescription)
}
let message = "notification Sent"
return try JSON(node:["success":message])
}
}//end of class
// request body
{
"to" : "cQDtm_someDeviceTokenReceivedFromClient",
"priority":"high",
"notification": {
"title":"Booking Rescheduled",
"body": "Cancelled Booking 7830593, for Mon, 12 March",
"sound":"default",
"badge": "100"
}
}

Represent a protobuf map as a json

I'm using grpcc, which is based on protobuf.js, to test my grpc service APIs.
My .proto file:
message MyRequest {
string userId = 1;
map<string, string> params = 2;
}
I tried the following json body to send a request:
{userId : "my_user_id" , params: { name: "my_name"}}
{userId : "my_user_id" , params: [{"name":"my_name"}] }
But this gives the following error:
Error: Illegal value for Message.Field....MyRequest.params of type string: object (expected ProtoBuf.Map or raw object for map field)
How to correctly represent a protobuf map as a json?
The proper json body would be the following:
{ "userId": "my_user_id", "params": { "name": "my_name" } }
What you've tried doing is an array of maps, which doesn't really mean anything in the context of protobuf. A map<string, string> is exactly the description of a json object, so more than one value would be represented the following way:
{ "params": { "key1": "value1", "key2": "value2" } }
No need for an array.

Why assert in #PactVerification?

I don't understand the use of assert in #PactVerification. To me it seams more like a complicated way of saying 1 == 1. For example:
import static org.assertj.core.api.Assertions.assertThat;
public class PactConsumerDrivenContractUnitTest {
#Rule
public PactProviderRuleMk2 mockProvider
= new PactProviderRuleMk2("test_provider", "localhost", 8080, this);
#Pact(consumer = "test_consumer")
public RequestResponsePact createPact(PactDslWithProvider builder) {
return builder
.given("test GET ")
.uponReceiving("GET REQUEST")
.path("/")
.method("GET")
.willRespondWith()
.body("{\"condition\": true, \"name\": \"tom\"}")
}
#Test
#PactVerification()
public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
//when
ResponseEntity<String> response
= new RestTemplate().getForEntity(mockProvider.getUrl(), String.class);
//then
assertThat(response.getBody()).contains("condition", "true", "name", "tom");
}
}
So first in "createPact" we state
body("{\"condition\": true, \"name\": \"tom\"}")
Then in givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody annotated #PactVerification we do this
assertThat(response.getBody()).contains("condition", "true", "name", "tom");
But why? We just said that! As far as I can see the assertion does not show up in the generated Pact file. It seams to fill no purpose?
In addition to that, I thought that the idea of contract testing was to reduce the need for integration test since they can break for example if test data changes. But here we still depend on test data. If there are no "Tom" in the Provider, then the test will fail. I primarily wanted to test if the contract is broken, not if the test data has changed.
The example given is a contrived one. In real life using Pact, you wouldn't do this. Your PactVerification would invoke a collaboration method/class/thing which is responsible for the external call to the service you are mocking.
So your assertions are then on what the collaborating function is doing.
Eg. A User Service might create an object with certain properties, that you know only are populated by that external call.
Testing assertions in your #PactVerification test method is not mandatory, yet still it might be very helpful. E.g. you may make a typo in your JSON body string and you wont be able to catch it in your test and it will break provider's pipeline. Assertions in this case have nothing to do with generated Pact file, they play role of a guard that checks in the end if the contract you have just defined (RequestResponsePact) matches all your expectations (assertions).
Also it is worth mentioning that your consumer contract tests should break only if provider tries to release a change that makes your expectations broken. And this is consumer's responsibility to write good contract tests. In your example you have defined following expectation:
#Pact(consumer = "test_consumer")
public RequestResponsePact createPact(PactDslWithProvider builder) {
return builder
.given("test GET ")
.uponReceiving("GET REQUEST")
.path("/")
.method("GET")
.willRespondWith()
.body("{\"condition\": true, \"name\": \"tom\"}")
}
This contract will be satisfied as long as condition == true and name == tom. This is over-specification of a response. You could define more flexible response with PactDslJsonBody DSL instead:
#Pact(consumer = "test_consumer")
public RequestResponsePact createPact(PactDslWithProvider builder) {
final DslPart body = new PactDslJsonBody()
.stringType("name", "tom")
.booleanType("condition", true);
return builder
.given("test GET ")
.uponReceiving("GET REQUEST")
.path("/")
.method("GET")
.willRespondWith()
.body(body)
.toPact();
}
This fragment will generate Pact file like:
{
"provider": {
"name": "providerA"
},
"consumer": {
"name": "test_consumer"
},
"interactions": [
{
"description": "GET REQUEST",
"request": {
"method": "GET",
"path": "/"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"body": {
"condition": true,
"name": "tom"
},
"matchingRules": {
"body": {
"$.name": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.condition": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
}
}
}
},
"providerStates": [
{
"name": "test GET "
}
]
}
],
"metadata": {
"pact-specification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.5.10"
}
}
}
The main difference is that this Pact file uses matchingRules to test if:
type of condition field is boolean
type of name field is String
For strings you can also use PactDslJsonBody.stringMatcher(name, regex, value) method if needed. It allows you to define regular expression that will be tested using current field value.

SWIFT 3 Post request with VIEWSTATE

I need to log in example.com/mobile/shared/default.aspx by using POST request
How do i get current ViewState and sending it after?
That is what i tried
(Alamofire)
func webRequest()
{
let parameters: Parameters = [
"name": "name",
"password": "password",
"enter": "Enter",
]
Alamofire.request("http://example.ru/mobile/shared/default.aspx", parameters: parameters).responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
}
I'm using Alamofire like this:
let Parameters = [
"name": "name",
"password": "password",
"enter": "Enter"]
var json : JSON = nil
Alamofire.request(URLString, method: method, parameters: Parameters)
.responseJSON { response in
switch response.result {
case .success(let data):
json = JSON(data)
print(json)
case .failure(let error):
print("Request failed with error: \(error)")
}
}
}
So after that you can parse your json like this for example:
if json != nil {
let token = json["token"].stringValue
}
But all of that depend of your server request params, and request response from your server.
Hope I helped you, Peace

Resources