No handler found for uri [/<index>/<type>/] and method [PUT] - elasticsearch

I'm trying to make a raw NodeJS http request to my elasticsearch index using the insert document api's auto increment id feature.
So this works with curl:
curl -XPOST http://host:3333/catalog/products -d '{ "hello": "world" }'
But when I try the same in nodejs via this:
var http = require('http');
var options = {
protocol: 'http:',
mehtod: 'PUT',
hostname: 'host',
port: 3333,
path: '/catalog/products/'
}
http.request(options, ...);
It returns this error:
No handler found for uri [/catalog/products/] and method [PUT]
However if I add an id to the end of that path it will work. What's wrong here?

The problem here is the way POST and PUT works, when you use POST, _id is optional, ES will generate a unique _id for you every time.
Here you are using PUT so _id is required, ES will either create a new document with that id or it will update the document with that id if it exists. You can read more about this.
Try indexing with POST request as you did with curl if you dont want to specify id
var options = {
protocol: 'http:',
hostname: 'host',
port: 3333,
path: '/catalog/products/',
method: 'POST' <--- specify method
}
Hope this helps!

Related

/* in transcoding from HTTP to gRPC

rpc CreateBook(CreateBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{parent=publishers/*}/books"
body: "book"
};
}
message CreateBookRequest {
// The publisher who will publish this book.
// When using HTTP/JSON, this field is automatically populated based
// on the URI, because of the `{parent=publishers/*}` syntax.
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
child_type: "library.googleapis.com/Book"
}];
Book book = 2 [(google.api.field_behavior) = REQUIRED];
string book_id = 3;
}
I don't understand post: "/v1/{parent=publishers/*}/books"
I thought publishers was a field in CreateBookRequest, then it populates to http, so it is something like this
post: "/v1/parent=publishers_field_value/books"
But publishers is not a field in CreateBookRequest
No, publishers is part of the expected value of the parent field. So suppose you have a protobuf request like this:
{
"parent": "publishers/pub1",
"book_id": "xyz"
"book": {
"author": "Stacy"
}
}
That can be transcoded by a client into an HTTP request with:
Method: POST
URI: /v1/publishers/pub1/books?bookId=xyz (with the appropriate host name)
Body:
{
"author": "Stacy"
}
If you try to specify a request with a parent that doesn't match publishers/*, I'd expect transcoding to fail.
That's in terms of transcoding from protobuf to HTTP, in the request. (That's the direction I'm most familiar with, having been coding it in C# just this week...)
In the server, it should just be the opposite - so given the HTTP request above, the server should come up with the original protobuf request including parent="publishers/pub1".
For a lot more information on all of this, see the proto defining HttpRule.

Pass query string parameters from WSO2 api gateway to AWS lambda

I need to pass query string parameters calling a WSO2 api gateway that calls an AWS lambda function.
I created the following lambda function in NodeJS in AWS:
exports.handler = async (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({
incoming:JSON.parse(event),
date: new Date(),
context: JSON.parse(context)
}),
};
};
Then I:
created a new API in wso2 publisher portal
added an endpoint of type lambda
configured a resource getTest for GET
added a query parameter parameter to the GET resource
When I call my API here is the result:
curl -X GET "https://localhost:8243/lambda/1/getTest?parameter=myValue" -H "accept: */*" -H "Authorization: Basic YWRtaW46YWRtaW4="
{
"statusCode":200,
"body":"{\"incoming\":{},\"date\":\"2021-06-22T08:09:36.027Z\",\"context\":{\"callbackWaitsForEmptyEventLoop\":true,\"functionVersion\":\"$LATEST\",\"functionName\":\"wso2get\",\"memoryLimitInMB\":\"128\",\"logGroupName\":\"/aws/lambda/wso2get\",\"logStreamName\":\"2021/06/22/[$LATEST]90a7f95746c644a7a5cc61ec8648228e\",\"invokedFunctionArn\":\"arn:aws:lambda:eu-west-1:659641230079:function:wso2get\",\"awsRequestId\":\"4e271442-6209-47d9-ab0c-277c6535b8bd\"}}"
}
How can I retrieve the parameter with value myValue in the lambda function?
You have to define you OpenAPI definition with this two kind of parameters:
Path Parameter
Query Parameter
I'll use wso2apim 2.6.0 and OpenAPI 2.0 definition...
Go to the /publisher and "Add a new API" with the "Design a New REST API"
Add a name , a contest ( ex. /mylambda ), and so on.
In the "API Definition" include a URL Pattern like
"/{id}/getTest" and check de GET method. Automatically a "Path parameter" is added with name "id".
Then add a new parameter named "parameter"
Save and in the implementation, set the "Endpoints" set the URL to:
"https://localhost:8243/lambda"
And that's all.
This is fixed in the latest pack. You can send path/query/header parameters, http method, and path along with the payload to Lambda. Make sure you define the parameter names at resource creation time as in 8.b.iii in [1]. Following is the format of the event object which Lambda receives.
{
"headers": {},
"pathParameters": {},
"queryStringParameters": {},
"body": {},
"httpMethod": "",
"path": ""
}
Note that, to enable param mapping for earlier versions, you have to put following config to deployment.toml file.
[apim.lambda_mediator_config]
pass_request_params = true
[1] https://apim.docs.wso2.com/en/latest/design/create-api/create-rest-api/create-a-rest-api/

How to run a graphql against faunadb from html client

I am totally new to graphql and faunadb, so plz bear with me if its a silly question.
I see I can run graphql query from the dashboard > GRAPHQL. e.g. Pasting the following code
query FindAllTodos {
allTodos {
data {
_id
title
completed
list {
title
}
}
}
}
and hitting the Run button. But how I can run this query from my html/js code which I want to run in browser?
In js I can create the clientsdk but not sure how to pass the above query?
import faunadb, { query as q } from 'faunadb';
let adminClient = new faunadb.Client({
secret: 'my-key'
});
On googling I found example which were using some FQL like structures like
adminClient.query(
q.Get(q.Ref(q.Collection('Todo'), '276653641074475527'))
)
.then((ret) => console.log(ret));
but how I can just pass the graphql query and get the same result, its returning me in right side pane of the graphql play ground.
You can use a client like curl or any GraphQL client.
With curl you can issue something like:
curl -X POST -H 'Authorization: Bearer <your key>' https://graphql.fauna.com/graphql -d '{ "query": "{ FindAllTodos{ data {_id title completed list { title }} }}"}'
I can get you 90% there but the code I present to you is written in TypeScript in an Angular app that uses HttpClient and RxJs Observables. With a little effort you can rewrite in JS using vanilla HTTP fetch.
By the way here is a video by Brecht De Rooms that helped me a lot:
https://www.youtube.com/watch?v=KlUPiQaTp0I
const SERVER_KEY = 'Your server key goes here';
const executeQuery = (query: string) => {
const headers = new HttpHeaders().set('Authorization', 'Bearer ' + SERVER_KEY);
return this.http.post<any>('https://graphql.fauna.com/graphql',
JSON.stringify({ query }), { headers });
}
const findAllTodos = () => {
const query = `query FindAllTodos {
allTodos {
data {
_id
title
completed
list {
title
}
}
}
}`;
return executeQuery(query);
}
findAllTodos().subscribe(console.log);
For me the hurdle was learning that the Fauna server expects JSON in this form:
{ "query": "query FindAllTodos {allTodos { ... and so forth and so on ..." }
That same structure applies when you run a mutation:
{ "query": "mutation AddTodo { ...etc... " }
By the way, if your query doesn't work the first time, which it probably won't, I recommend opening your browser's developer's tools Network tab and inspect the request that was sent to the Fauna server. Look at the Response. There will be error information in there. The response status will be 200(OK) even when there are errors. You need to look inside the response to check for errors.

How to do POST request to Grape REST API using params block compatible with Swagger

I am using grape to build a REST API, I am having some trouble with params options.
This is how I do a POST request:
# Curl Request
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"title":"hello","body":"world"}'
# {"error":"article is missing"}
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"article":{title":"hello","body":"world"}}'
# {"error":"article is invalid"}
As you can see if I omit article it fails article missing, If i put article and it fails article invalid.
This is the code, I am using grape-entity.
# Entity
module API
module Entities
class Article < Grape::Entity
expose :title, documentation: { type: 'string', desc: 'Title' }
expose :body, documentation: { type: 'string', desc: 'Body' }
end
end
end
# API
desc "Create an article"
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
post '/articles' do
puts params
article = Article.create(params(:title, :body))
represent(article, env)
end
# Add Swagger Docs
add_swagger_documentation mount_path: 'api/doc',
api_version: 'v1',
markdown: GrapeSwagger::Markdown::KramdownAdapter,
hide_documentation_path: true,
base_path: Application.config.base_path,
models: [API::Entities::Article]
Specifically the problem is caused by params block, it requires an :article of type API:Entities::Article.
Also note that, I am using add-swagger-documentation, and this code
produces correct swagger documentation, so the solution have to be
fully compatible with swagger. What is the correct usage of params
block without offending the swagger.
I'm not sure what you're trying to accomplish here. I guess you want to change your post method in a way that it accepts a JSON like this:
{ attribute1: value, attribute2: value }
instead of
{ article: { attribute1: value, attribute2: value } }
In this case, you have to change your params block to something like this
params do
requires :attribute1, type: String, documentation: { eg: "aklsdfj" }
requires :attribute2, type: String, documentation: { eg: "aklsdfj" }
end
instead of
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
The params block above is expecting a JSON containing an article attribute composed by every attribute defined in the entity API::Entities::Article.
In fact, Grape doesn't accept entity objects as a type for a parameter.

Twitter typeahead.js remote and search on client

As of my understanding typeahead.js got three ways of fetching data.
Local: hardcoded data
Prefetch: Load a local json file, or by URL
Remote: Send a query to the backend which responds with matching results
I want to fetch all data from the backend and then
process it on the client.
The data my server responds with got the following structure:
[{id:2, courseCode:IDA530, courseName:Software Testing, university:Lund University},
{id:1, courseCode:IDA321, courseName:Computer Security, university:Uppsala University}, ...]
I want it to search on all fields in each entry. (id, courseCode, courseName, university)
I wanna do more on the client and still fetching one time for each user (instead of every time a user are typing), I probably misunderstood something here but please correct me.
You should re-read the docs. Basically there are two things you need:
Use the prefetch: object to bring all the data from the backend to the client only once (that's what you are looking for, if I understand correctly.)
Use a filter function to transform those results into datums. The returned datums can have a tokens field, which will be what typeahead searched by, and can be built from all your data.
Something along the lines of:
$('input.twitter-search').typeahead([{
name: 'courses',
prefetch: {
url: '/url-path-to-server-ajax-that-returns-data',
filter: function(data) {
retval = [];
for (var i = 0; i < data.length; i++) {
retval.push({
value: data[i].courseCode,
tokens: [data[i].courseCode, data[i].courseName, data[i].university],
courseCode: data[i].courseCode,
courseName: data[i].courseName,
template: '<p>{{courseCode}} - {{courseName}}</p>',
});
}
return retval;
}
}
}]);

Resources