Erlang Cowboy Rest Handler for POST request - rest

The response is 415 (Unsupported Media Type) .
Client Side Code:
$.ajax({
url: "/book",
//contentType: 'application/json',
data: {action: "hello", method: "json"},
dataType: "json",
type: "POST",
complete: function(a, b) {
console.log(a);
console.log(b);
}
});
Server Side Code:
content_types_provided(Req, State) ->
{[
{<<"application/json">>, handle_to_all}
], Req, State}.
handle_to_all(Req, State) ->
Body = <<"{\"rest\": \"Hello World!\"}">>,
{Body, Req, State}.
If I update the type from "POST" to "GET" from client side, everything is okay.
Anything I missed?

content_types_provided method of cowboy accepts only GET and HEAD
Go through the following link and change the code accordingly
https://ninenines.eu/docs/en/cowboy/1.0/manual/cowboy_rest/

You can use cowboy_rest, implement the content_types_accepted/2 callback method like so:
content_types_accepted(Req, State) ->
case cowboy_req:method(Req) of
{<<"POST">>, _ } ->
Accepted = {[{<<"application/json">>, put_json}], Req, State};
{<<"PUT">>, _ } ->
Accepted = {[{<<"application/json">>, post_json}], Req, State}
end,
Accepted.
I think this way you can have separate handlers for different HTTP Verbs/Methods. This gives you cleaner code too :)
And the various handlers:
%% handle http put requests
put_file(Req, State) ->
{true, Req, State}.
%% handle http post requests
post_json(Req, State) ->
{true, Req, State}.

Related

Istio Distributed Tracing shows just 1 span

I'm following this guide, with Zipkin.
I have 3 microservices involed, A -> B -> C, I'm propagating headers from A to B and from B to C.
But in the Zipkin dashboard I only see entries for A -> B and B -> C, not A -> B -> C.
Those are the headers:
[
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"x-ot-span-context"
]
I can see that in B x-b3-parentspanid is null and I guess that's wrong, but the other are working I think...how is it possible?
EDIT:
added code snippets to show headers propagation
A -> B propagation:
app.post("/job", (req, res) => postJob(req.body, req.headers).then((response) => res.send(response)))
...
const postJob = (job, headers) => rp({
method: "POST",
uri: `${API_ENDPOINT}/api/job`,
json: true,
body: job,
headers: Object.keys(headers).filter((key) => TRACING_HEADERS.includes(key)).map((key) => headers[key])
})
B -> C propagation:
#PostMapping("/api/job")
#ResponseBody
fun publish(
#RequestBody job: Job,
#RequestHeader("x-request-id") xreq: String?,
#RequestHeader("x-b3-traceid") xtraceid: String?,
#RequestHeader("x-b3-spanid") xspanid: String?,
#RequestHeader("x-b3-parentspanid") xparentspanid: String?,
#RequestHeader("x-b3-sampled") xsampled: String?,
#RequestHeader("x-b3-flags") xflags: String?,
#RequestHeader("x-ot-span-context") xotspan: String?
): JobResponse = jobsService.publishJob(
job, mapOf(
"x-request-id" to xreq,
"x-b3-traceid" to xtraceid,
"x-b3-spanid" to xspanid,
"x-b3-parentspanid" to xparentspanid,
"x-b3-sampled" to xsampled,
"x-b3-flags" to xflags,
"x-ot-span-context" to xotspan
)
)
...
fun publishJob(job: Job, headers: Map<String, String?>): JobResponse {
val enabled = restTemplate.exchange(
"${gatekeeperConfiguration.endpoint}/",
HttpMethod.GET,
HttpEntity(headers),
EnabledResponse::class.java
).body
if (!enabled!!.isEnabled) // TODO we intentionally want this to crash if body is null
return JobResponse(JobRequestStatus.REJECTED)
return if (this.queue.publish(job)) JobResponse(JobRequestStatus.OK)
else throw RuntimeException("I don't know what to do, yet")
}
Object.keys(headers).filter((key) => TRACING_HEADERS.includes(key)).map((key) => headers[key]) returns an array.
What you want is:
Object.keys(headers)
.filter(key => TRACING_HEADERS.includes(key))
.reduce((obj, key) => {
obj[key] = headers[key];
return obj;
}, {})
I'm pretty sure this isn't an istio / distributed tracing issue ;-)
b3-propagation of x-b3-parentspanid (https://github.com/openzipkin/b3-propagation) can be configured in your application.yml by adding:
opentracing:
jaeger:
enable-b3-propagation: true

Express rest api call with angular 2 How to

Greeting,
I have a trivial issue on calling a rest api from angular 2.
I have a rest api endpoint:
api/room/byName/:roomName
if I use restfull tools like postman etc and call api http://localhost:3000/api/room/byName/roomname1 this works fine and get result.
But when i can call this from angular2 , the rest api is not even being called.
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get('/api/room/byName',{search:params})
.map((response: Response) => response.json());
I am sure, I am not calling it properly. Appreciate your help on how to call it from angular 2.
Thanks
Edit
After getting advice this is my code now but still no luck:
Angular call:
return this.http
.get('/api/room/byName/'+roomName)
.map((res: Response) => res.json());
Express endpoint:
var rooms = express.Router();
rooms.get('/byName/:roomName', function(req,res){
var roomn = req.params.roomName;
console.log('Looking by roomName: ' + roomn);
Room.findOne({ "roomName": roomn }, function(err, rooms) {
if (err) {
next(err);
} else {
res.json(rooms);
}
});
});
This works fine if i call the endpoint from browser:
http://localhost:3000/api/room/byName/test
The Http get takes only url and not body as parameter.It is not a post to have body.
Try:
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get(`/api/room/byName/${roomName}`)
.map((response: Response) => response.json());
first make sure you're enabled CORS
2nd: change this
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get('/api/room/byName',{search:params})
.map((response: Response) => response.json());
to:
return this
.http
.get('/api/room/byName/'+ roomName)
.map((response: Response) => response.json());

setting interval for notifications

The following coffeeScript is running properly without the references to setUpdateInterval.
class Notifications
constructor: ->
#notifications = $("[data-behavior='notifications']")
#setup() if #notifications.length > 0
setUpdateInterval()
setup: ->
$.ajax(
url: "/notifications.json"
dataType: "JSON"
method: "GET"
success: #handleSuccess
)
handleSuccess: (data) =>
items = $.map data, (notification) ->
"<li class='active'><a href='#{notification.url}'>#{notification.actor} #{notification.notifiable.type}</a></li>"
$("[data-behavior='unread-count']").text(items.length)
$("[data-behavior='notification-items']").html(items)
setUpdateInterval: (notifications) ->
callback = #setup.bind(this)
setInterval( callback, 15000 )
jQuery ->
new Notifications
What is incorrect with the additional line and bloc inserted?
Based on comment, the following functions.
constructor: ->
#notifications = $("[data-behavior='notifications']")
#setUpdateInterval()
#setup() if #notifications.length > 0
setup: ->
$.ajax(
url: "/notifications.json"
dataType: "JSON"
method: "GET"
success: #handleSuccess
)
setUpdateInterval: (notifications) ->
callback = #setup.bind(this)
setInterval( callback, 15000 )

calling 2 https requests simultaneously in hubot coffescript

module.exports = (robot) ->
robot.respond /log (.*)/i, (msg) ->
group = "test"
incident_message = msg.match[0]
service_key = keys[group]
curtime = new Date().getTime()
incident_key = "hubot/#{curtime}"
reporter = msg.message.user.name
query = {
"service_key": service_key,
"incident_key": incident_key,
"event_type": "trigger",
"description": "Change Log #{reporter}",
"details": "#{incident_message}"
}
string_query = JSON.stringify(query)
content_length = string_query.length
msg
.http("https://events.pagerduty.com/generic/2010-04-15/create_event.json")
.headers
"Content-type": "application/json",
"Content-length": content_length
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
msg
.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
I am trying to auto acknowledge an event triggered in pagerduty. The first http request takes effect. But the second http request (last line of the code) never takes effect. I have tried varipus combinations. But it does not help. I am new to coffeescript and only use it for hubot.Can anyone help me ?
First, you don't specify what HTTP action you are doing:
msg.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
Should end with .get() or .post().
Also, possibly due to bad paste, your indentation if off a bit in the middle:
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
Should be:
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
Another thing, due to nature of NodeJS, these HTTP calls are made asynchronously, and there is a good chance that second call finishes before first one does. To avoid that, run the second request from callback of the first one:
msg
.http("https://events.pagerduty.com/generic/2010-04-15/create_event.json")
.headers
"Content-type": "application/json",
"Content-length": content_length
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
msg
.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
.get()
else
msg.send "There was an error sending your log."
You can find some examples of Hubot HTTP requests and other scripting tricks here.

AJAX POST issue - [[NoSuchElementException: None.get]]

I can't seem to get the POST parameters to come through from an AJAX javascript POST. The error is:
#6angl7689 - Internal server error, for request [POST /myRoute] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[NoSuchElementException: None.get]]
Route:
POST /myRoute controllers.Application.testPost
Controller code:
def myForm = Form(
tuple(
"valOne" -> text,
"valTwo" -> text))
def testPost() = Action { implicit request =>
val (valOne, valTwo) = myForm.bindFromRequest.get // Errors here
println("valOne: " + valOne)
println("valTwo: " + valTwo)
Ok
}
CoffeeScript client-side:
params =
valOne: 'valOne'
valTwo: 'valTwo'
$.ajax
type: 'POST'
url: '/myRoute'
data: params
Update your client code,
$.ajax(
type: 'POST'
url: '/myRoute'
data: {valOne: 'valOne', valTwo: 'valTwo'}
);
This should work