Is there any postman like client for protobuffer - protocol-buffers

I want to develop a protocol-buffer type RESTful API that replaces JSON with protocol-buffer.
For example, a Spring Boot implement:
#RestController
#RequestMapping("account")
public class AccountController {
#RequestMapping(
path = "ListAccount",
method = RequestMethod.POST,
consumes = {"application/x-protobuf", "application/x-protobuf;charset=UTF-8"},
produces = {"application/x-protobuf", "application/x-protobuf;charset=UTF-8"})
public ListAccountResponse listAccount(ListAccountRequest request) {
// do something
ListAccountResponse response = ListAccountResponse.newBuilder().build();
return response;
}
}
syntax = "proto3";
option java_multiple_files = true;
option java_package = "account.proto.api";
package account.api;
import "common/pagination.proto";
import "common/valid.proto";
import "account/data/account.proto";
message ListAccountRequest {
common.Pagination page = 1 [(valid.validate) = true];
}
message ListAccountResponse {
repeated account.data.Account accounts = 1;
common.Pagination page = 2;
}
It seems that no a GUI client like postman for testing protocol-buffer API, which make me writing a tester in java. I will appreciate it if someone can tell me the answer.

You can use BloomRpc.First of all you should import your proto files and after that change format of request according to your rpc service.

you can use protoman A Postman-like API client for protobuf-based messages.
https://github.com/spluxx/Protoman

Related

Send a ServerSentEvent from another Method

I'm trying to implement a Server Sent Event Controller for updating my Web Browser Client with the newest Data to display.
This is my current Controller which sends the list of my data every 5 seconds. I want to send a SSE everytime I save my data in another service.
I read about using a channel, but how do I consume it with a Flux?
#GetMapping("/images-sse")
fun getImagesAsSSE(
request: HttpServletRequest
): Flux<ServerSentEvent<MutableList<Image>>> {
val subdomain = request.serverName.split(".").first()
return Flux.interval(Duration.ofSeconds(5))
.map {
ServerSentEvent.builder<MutableList<Image>>()
.event("periodic-event")
.data(weddingService.getBySubdomain(subdomain)?.pictures).build()
}
}
Example code for controller:
package sk.qpp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;
import java.util.concurrent.atomic.AtomicLong;
#Controller
#Slf4j
public class ReactiveController {
record SomeDTO(String name, String address) {
}
private final Sinks.Many<SomeDTO> eventSink = Sinks.many().multicast().directBestEffort();
#RequestMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<SomeDTO>> sse() {
final AtomicLong counter = new AtomicLong(0);
return eventSink.asFlux()
.map(e -> ServerSentEvent.builder(e)
.id(counter.incrementAndGet() + "")
//.event(e.getClass().getName())
.build());
}
// note, when you want this to work in production, ensure, that http request is not being cached on its way, using POST method for example.
#ResponseStatus(HttpStatus.OK)
#ResponseBody
#GetMapping(path = "/sendSomething", produces = MediaType.TEXT_PLAIN_VALUE)
public String sendSomething() {
this.eventSink.emitNext(
new SomeDTO("name", "address"),
(signalType, emitResult) -> {
log.warn("Some event is being not send to all subscribers. It will vanish...");
// returning false, to not retry emitting given data again.
return false;
}
);
return "Have a look at /sse endpoint (using \"curl http://localhost/sse\" for example), to see events in realtime.";
}
}
Sink is used as some "custom flux", where you can put anything (using emitNext), and take from it (using asFlux() method).
After setting up sample controller, open http://localhost:9091/sendSomething in your browser (i.e. do GET request on it) and in console issue command curl http://localhost:9091/sse to see your sse events (after each get request, new should come). It is possible also to see sse events directly in chromium browser. Firefox does try to download and save it to filesystem as file (works also).
I finally got it working. I also added user specific updates with a cookie.
Here is my SSE Controller
#RestController
#RequestMapping("/api/sse")
class SSEController {
val imageUpdateSink : Sinks.Many<Wedding> = Sinks.many().multicast().directBestEffort()
#GetMapping("/images")
fun getImagesAsSSE(
request: HttpServletRequest
): Flux<ServerSentEvent<MutableList<Image>>> {
val counter: AtomicLong = AtomicLong(0)
return imageUpdateSink.asFlux()
.filter { wedding ->
val folderId = request.cookies.find {cookie ->
cookie.name == "folderId"
}?.value
folderId == wedding.folderId
}.map { wedding ->
ServerSentEvent.builder<MutableList<Image>>()
.event("new-image")
.data(
wedding.pictures
).id(counter.incrementAndGet().toString())
.build()
}
}
}
In my Service where my data is updated:
val updatedImageList = weddingRepository.findByFolderId(imageDTO.folderId)
sseController.imageUpdateSink.tryEmitNext(
updatedImageList
)
My Javascript looks like this:
document.cookie = "folderId=" + [[${wedding.folderId}]]
const evtSource = new EventSource("/api/sse/images")
evtSource.addEventListener("new-image", function(alpineContext){
return function (event) {
console.log(event.data)
alpineContext.images = JSON.parse(event.data)
};
}(this))

How to send the data from a server to a client in the embedded messages in C++ using grpc?

I am implementing a simple client-server grpc-c++ based application. In the Hello rpc, I am taking the request and sending the fields of another message called SeverInfo as response. The problem is I exactly don't know how to send this ServerInfo data to a client from server side. We basically use set_fieldname(ex: set_name) for general datatypes to send the data but how should we send this serverInfo data to HelloResponse and then to HelloRequest. Can somebody please help me??
Below I am attaching the proto file.
syntax = "proto3";
package sample;
service Sample {
rpc Hello(HelloRequest) returns (HelloReply){}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
ServerInfo sinfo = 1;
}
message ServerInfo {
string name = 1;
string os = 2;
}
you can define another rpc in your service definitions like
service Sample {
rpc Hello(HelloRequest) returns (HelloReply){}
rpc GetServerInfo(HelloRequest) returns (ServerInfo){}
}
would that work for you?
Here is the answer that worked for me. Thank you.
ServerInfo* serverinfo=new ServerInfo();
serverinfo->set_name("");
serverinfo->set_os("");
HelloReply* rep;
rep->set_allocated_server(serverinfo);

Spring Traverson follow relative path ignores baseUri

I'm trying to use Traverson in my Spring Boot application to consume an external HAL-api. While doing so I get the exception org.apache.http.ProtocolException: Target host is not specified on the first hop, i.e. Traverson calls my baseUri without problems and with set target host, but seems to "forget" the host on the first hop.
And this is the code calling it:
override fun doStuff() {
// baseUri gets injected by class and is of form "https://my.host.com"
val startUri = UriComponentsBuilder.fromUriString(baseUri)
// If dms is declared as first hop, Traverson would call baseUri before first hop which returns a html website and results in an error -> dms has to be part of Traverson baseUri
.pathSegment("dms")
.build()
.toUri();
val authHeader = HttpHeaders()
// bearerToken gets injected by class and is not relevant for the problem
authHeader.set(HttpHeaders.AUTHORIZATION, bearerToken)
val restTemplate = RestTemplateBuilder()
.rootUri(baseUri)
.defaultHeader(HttpHeaders.AUTHORIZATION, bearerToken)
.build()
// httpRequestFactory gets injected by class and is used to configure SSL, should not matter for the problem
restTemplate.requestFactory = httpRequestFactory
val repoId: String = Traverson(startUri, MediaTypes.HAL_JSON)
.setRestOperations(restTemplate)
.follow("$._links.allrepos.href")
.withHeaders(authHeader)
.toObject("$.repositories[0].id")
log.debug("Repo id is $repoId")
}
This is the return of the Traverson baseUri (https://my.host.com/dms):
{
_links: {
allrepos: {
href: "/dms/r"
}
}
}
When executing this code, Traverson get's the link I'm searching for ("/dms/r") but when trying to follow it, it executes a call to "/dms/r" instead of "https://my.host.com/dms/r".
Am I missing something?
Every bit of help is very much appreciated!
EDIT 1:
It is possible to achieve my goal with following code. But if I have to resort to this option, I would instead use restTemplate directly without url discovery, since Traverson is just too inconvenient to use in this case.
val allReposLink = Traverson(startUri, MediaTypes.HAL_JSON)
.setRestOperations(restTemplate)
.follow("$._links.allrepos.href")
.withHeaders(headers)
.asLink()
.href
val allReposUri = UriComponentsBuilder.fromUriString(baseUri)
.pathSegment(allReposLink)
.build()
.toUri()
val repoId = Traverson(allReposUri, MediaTypes.HAL_JSON)
.setRestOperations(restTemplate)
.follow("$.repositories[0].id")
.withHeaders(headers)
.asLink()
.href
It should be possible to do it like this:
// DOES NOT WORK
val repoId: String = Traverson(startUri, MediaTypes.HAL_JSON)
.setRestOperations(restTemplate)
.follow("allrepos")
.withHeaders(headers)
.toObject("$.repositories[0].id")

jmeter - how to make a groovy script easier to maintain for extentreports

Below is a script that helps me build an extentreport for jmeter. It is a JSR223 PostProcessor element. It's working nicely however, the problem is that I have it duplicated after every HTTP Request in the script. I have several scripts with 100's of HTTP requests that would need essentially a copy of the same PostProcessor groovy script. This = hard to maintain!
I have tried splitting common parts into an external groovy script that I tried calling on the JSR223 PostProcessor. I also tried chunking up the bits of the script and putting the values into a csv so that I could just update the csv values if anything changed.
I'm sure there's a cleaner/better way to do this but I'm still learning so I'm not sure of the best way to make this easier to maintain. Here's the JSR223 PostProcessor. The only bit that changes with each http request is the "//test result" section
import com.relevantcodes.extentreports.ExtentReports;
import com.relevantcodes.extentreports.ExtentTest;
import com.relevantcodes.extentreports.LogStatus;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
//configure object for response data
def response = prev.getResponseDataAsString();
//configure extentreports objects
ExtentReports report;
ExtentTest testLogger;
//set location for file and report config
String resultsPath = "C:/portalQA/Automation/Results/";
String configPath = "C:/portalQA/Automation/JMeter/TestReportConfig/";
String reportPath =
resultsPath+"Login_Results_${reportDate}_${currentTime}_${testenv}.html";
File file = new File(reportPath);
if (!file.exists()) {
//if file does not exist, create it
report = new ExtentReports(reportPath, true);
report.loadConfig( new File(configPath+"extent-config.xml"));
} else {
//else append to existing report
report = new ExtentReports(reportPath, false);
report.loadConfig( new File(configPath+"extent-config.xml"));
}
//test result
testLogger = report.startTest("Authenticate");
testLogger.assignCategory("Initialize Session");
if (response.contains("com.blah.portal.model.User")) {
testLogger.log(LogStatus.PASS, "Logged in with: ${username}");
testLogger.log(LogStatus.INFO, response);
} else {
testLogger.log(LogStatus.FAIL, "Could not authenticate session");
testLogger.log(LogStatus.INFO, response);
}
log.info("Authenticate");
print("Authenticate print");
report.endTest(testLogger);
report.flush();
I see two options:
I suggest using JSR223 Listener instead. First of all, that way you will only have 1 listener in your script, which resolves your original problem, but it is a better option for writing into file in general, since listener has only one instance for all running threads, so you won't be creating a race condition when writing to file.
If you rather have a post-processor, you can put it on higher level (not under any particular sampler) which will cause it to run after each request within the same scope or below.
For example, configuration like
Thread Group
Post-processor
Sampler 1
...
Sampler N
Will cause Post-processor to run after each Sampler 1...Sampler N
In both cases you may need to check which sampler you are processing, and skip those you don't want to add to your report (easiest way to do it, is to come up with some name convention for excluded samplers)
I also faced the same challenge. In my case I need to check if JSON response from REST service was correct. I solved it in the following way.
I've created a JSR223 PreProcessor under the script root. It contains my custom class to handle JSON parsing and asserts.
import groovy.json.JsonSlurper
import org.apache.jmeter.assertions.AssertionResult
class CustomAssert {
def parseResponse(json) {
def jsonSlurper = new JsonSlurper()
return jsonSlurper.parseText(json)
}
def assertResult(assertionResult, expectedResult, actualResult) {
if (!expectedResult.equals(actualResult)) {
assertionResult.setFailure(true);
assertionResult.setFailureMessage("Expected ${expectedResult} but was ${actualResult}");
}
}
}
vars.putObject('customAssert', new CustomAssert())
Note the last line:
vars.putObject('customAssert', new CustomAssert())
I put an instance of my CustomAssert to vars.
Then under my HTTP Requests I've added JSR233 Assertion
def a = vars.getObject('customAssert')
def response = a.parseResponse(prev.getResponseDataAsString())
a.assertResult(AssertionResult, 'DRY', response.sensorResultHolderUIs[0].result.toString())
a.assertResult(AssertionResult, 'DRY', response.sensorResultHolderUIs[1].result.toString())
a.assertResult(AssertionResult, 'DRY', response.sensorResultHolderUIs[2].result.toString())
It basically retrieves the instance of CustomAssert from vars and calls its methods. I can put as many JSR233 Assertions as I want. The only code that is copied is those two lines on top:
def a = vars.getObject('customAssert')
def response = a.parseResponse(prev.getResponseDataAsString())
To sum up:
Take the common part of your code (that doesn't have to be copied).
Wrap it in a class.
Put the class in JSR233 PreProcessor under the root and export its instance via vars
Take the rest of your code and adjust it to use class defined in 2.
Put that code in as many JSR233 Assertions as you want remembering to retrieve the instance created in 3. from vars
Thank you user1053510. Your advice lead me to build my own JSR223 Listener that renders the report. Below is the code in my JSR223 Listener:
import com.aventstack.extentreports.*;
import com.aventstack.extentreports.reporter.*;
import com.aventstack.extentreports.markuputils.*;
ExtentHtmlReporter htmlReporter;
ExtentReports extent;
ExtentTest test;
// create the HtmlReporter
htmlReporter = new ExtentHtmlReporter("C:/AUTO_Results/Results_${testApp}_${reportDate}_${currentTime}_${testenv}.html");
//configure report
htmlReporter.config().setCreateOfflineReport(true);
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setDocumentTitle("${testApp} Results");
htmlReporter.config().setEncoding("utf-8");
htmlReporter.config().setReportName("${testApp} Results ${reportDate}_${currentTime}_${testenv}");
htmlReporter.setAppendExisting(true);
// create ExtentReports
extent = new ExtentReports();
// attach reporter to ExtentReports
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
// Show Env section and set data on dashboard
extent.setSystemInfo("Tool","JMeter");
extent.setSystemInfo("Test Env","${testenv}");
extent.setSystemInfo("Test Date","${reportDate}");
extent.setSystemInfo("Test Time","${currentTime}");
//stringify test info
String threadName = sampler.getThreadName();
String samplerName = sampler.getName();
String requestData = props.get("propRequestData");
String respCode = props.get("propRespCode");
String respMessage = props.get("propRespMessage");
String responseData = props.get("propResponse");
// create test
test = extent.createTest(threadName+" - "+samplerName);
//test.assignCategory("API Testing");
// analyze sampler result
if (vars.get("JMeterThread.last_sample_ok") == "false") {
log.error("FAILED: "+samplerName);
print("FAILED: "+samplerName);
test.fail(MarkupHelper.createLabel("FAILED: "+sampler.getName(),ExtentColor.RED));
} else if (vars.get("JMeterThread.last_sample_ok") == "true") {
if(responseData.contains("#error")) {
log.info("FAILED: "+sampler.getName());
print("FAILED: "+sampler.getName());
test.fail(MarkupHelper.createLabel("FAILED: "+sampler.getName(),ExtentColor.RED));
} else if (responseData.contains("{")) {
log.info("Passed: "+sampler.getName());
print("Passed: "+sampler.getName());
test.pass(MarkupHelper.createLabel("Passed: "+sampler.getName(),ExtentColor.GREEN));
}
} else {
log.error("Something is really wonky");
print("Something is really wonky");
test.fatal("Something is really wonky");
}
//info messages
test.info("RequestData: "+requestData);
test.info("Response Code and Message: "+respCode+" "+respMessage);
test.info("ResponseData: "+responseData);
//playing around
//markupify json into code blocks
//Markup m = MarkupHelper.createCodeBlock(requestData);
//test.info(MarkupHelper.createModal("Modal text"));
//Markup mCard = MarkupHelper.createCard(requestData, ExtentColor.CYAN);
// test.info("Request "+m);
// test.info(mCard);
// test.info("Response Data: "+MarkupHelper.createCodeBlock(props.get("propResponse")));
// test.info("ASSERTION MESSAGE: "+props.get("propAssertion"));
// end the reporting and save the file
extent.flush();
Then in each threadgroup I have a BeanShell Assertion with these lines:
//request data
String requestData = new String(prev.SamplerData);
//String requestData = new String(requestData);
props.put("propRequestData", requestData);
//response data
String respData = new String(prev.ResponseData);
//String respData = new String(prev.getResponseDataAsString());
props.put("propResponse", respData);
//response code
String respCode = new String(prev.ResponseCode);
props.put("propRespCode",respCode);
//response message
String respMessage = new String(prev.ResponseMessage);
props.put("propRespMessage",respMessage);

Spring 3 RESTful return on POST (create)

I am new to RESTful services and their implementation on Spring 3. I would like your opinion on the best practices for returning type when a client creates a new resource in my server.
#RequestMapping(method = RequestMethod.POST,
value = "/organisation",
headers = "content-type=application/xml")
#ResponseStatus(HttpStatus.CREATED)
public ??? createOrganisation(#RequestBody String xml)
{
StreamSource source = new StreamSource(new StringReader(xml));
Organisation organisation = (Organisation) castorMarshaller.unmarshal(source);
// save
return ???;
}
A simple choice would be javax.ws.rs.core.Response, found in the Java EE's own restful services package. It - simply - tells what the web server should answer to the HTTP request.
For instance:
if (organisation != null)
return Response.ok().build();
else
return Response.serverError().build();
Custom response headers and other exotic things like that are possible with that return type too, but I don't think that would match with "best practices".
uh, I missed that #ResponseStatus(HttpStatus.CREATED)... I guess my answer was not much of help.
Maybe this will help instead: How to return generated ID in RESTful POST?
I would go for a ResponseEntity<byte[]> and you would have take care of the marshalling of your response on your controller method. Notice that you are basically scrapping the V in MVC, there is a MarshallingView on Spring but from experience I consider the previous solution much more flexible and easier to understand.
It is a good idea to return the newly created entity(with the generated id) wrapped in ResponseEntity. You can also set the HttpStatus in ResponseEntity based on the result of the operation.
#RequestMapping(method = RequestMethod.POST,
value = "/organization",
headers = "content-type=application/xml")
public ResponseEntity<Organization> createOrganisation(#RequestBody String xml) {
StreamSource source = new StreamSource(new StringReader(xml));
Organization organisation = (Organization) castorMarshaller.unmarshal(source);
// save
return new ResponseEntity<Organization>(organization, HttpStatus.OK);
}

Resources