ES6 Proxy wrapper - node.js

Modern ECMAScript-262 from 6 version supports Proxy object, which allows to intercept custom object invocations (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy )
By using Proxy-object, user can write something like obj.func1(123).func2('ABC').something, there nothing right to obj is not existing actually. Of course, by proper Proxy declaration, this chain can exist. The simplest way is return new Proxy on every property access and function invocation.
But is there way to automate this process, maybe some NPM library? The goal is transform custom free-form expression with Proxy to declarative string.
Upper example will transform to something like:
const result = obj.func1(123).func2('ABC').something;
result.__INVOCATION_VIEW__ === [
{ type: 'function', name: 'func1', args: [123] },
{ type: 'function', name: 'func2', args: ['ABC'] },
{ type: 'get', name: 'something' }
]
Pure theoretically, solution is possible anyway, because any entity in invocation chain is available as string in subsequent Proxy. But implementation is much complex. Maybe there is existing library for it?

Related

How to add TypeScript Interface to shorthand variable?

How to set TypeScript interface to variable looking like this:
const { body, statusCode } = await got.post('smth', requestOpts)
How can I set the interface to ex. body. I would like to assign there an interface with potential requests from the server. An interface that I'm willing to implement looks like that:
interface ResponseBody {
data: [{ username: string }]
}
I tried different things to attach this interface to the upper variable body but I'm getting build errors. The only workaround that I have here is to do not use shorthand variable but that's not my goal - I wonder if there are solutions for such issue.
TypeScript Playground
You'd need to annotate the whole object, like this:
const { body, statusCode }: { body: ResponseBody, statusCode: number } =
await got.post<ResponseBody>('users', requestOpts)
While it would be nice if you could annotate the individual destructured variables inside the object, this is not currently possible. The syntax const { body: ResponseBody } = ... can't work because JavaScript interprets this as assigning to a new variable name (so there'd be a variable named ResponseBody holding the value that was in the body property). Perhaps something like const { body::ResponseBody, statusCode::number } would work instead, as requested in microsoft/TypeScript#29526. But for now this is not possible, and you have to annotate the whole object.
That's the answer to the question as asked.
Do note that for your particular example, though, the got.post() method has a call signature that's generic in the type you expect the body property to be. So you can write
const { body, statusCode } = await got.post<ResponseBody>('users', requestOpts);
to get a strongly typed body variable with a minimum of extra keystrokes.
Playground link to code

What does Depends with no parameter do?

I am trying to implement JWT with fastapi.
Currently looking at the following libraries
fastapi-users
FastAPI JWT Auth
In both cases, I see Depends() in method parameter.
What does Depends do when there is nothing in the parameter?
https://github.com/frankie567/fastapi-users/blob/master/fastapi_users/router/auth.py
#router.post("/login")
async def login(
response: Response, credentials: OAuth2PasswordRequestForm = Depends()
):
https://indominusbyte.github.io/fastapi-jwt-auth/usage/basic/
#app.post('/login')
def login(user: User, Authorize: AuthJWT = Depends()):
I undestand when there's a function inside the parameter but would you teach me what it does when there's no parameter with Depends?
Depends() without arguments is just a shortcut for classes as dependencies.
You see that we are having some code repetition here, writing CommonQueryParams twice:
commons: CommonQueryParams = Depends(CommonQueryParams)
FastAPI provides a shortcut for these cases, in where the dependency is specifically a class that FastAPI will "call" to create an instance of the class itself.
For those specific cases, you can do the following:
Instead of writing:
commons: CommonQueryParams = Depends(CommonQueryParams)
...you write:
commons: CommonQueryParams = Depends()
You declare the dependency as the type of the parameter, and you use Depends() as its "default" value (that after the =) for that function's parameter, without any parameter in Depends(), instead of having to write the full class again inside of Depends(CommonQueryParams).
In both cases, I see Depends() in method parameter. What does Depends do when there is nothing in the parameter?
It's a great question.
Assume you have the following code.
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from typing import Optional
class Location(BaseModel):
city: str
country: str
state: str
app = FastAPI()
#app.post("/withoutdepends")
async def with_depends(location: Location):
return location
#app.post("/withdepends")
async def with_depends(location: Location = Depends()):
return lcoation
We have the same Location model in two different endpoints, one uses Depends other one not.
What is the difference?
Since FastAPI is based on OpenAPI specification, we can start discovering the difference from auto-generated Swagger's docs.
This is without Depends, it expects a Request Body.
This is with Depends, it expects them as Query parameters.
How this is useful and how it works?
Actually, this is it, it expects a Callable there.
But when you use a Pydantic Model with Depends, it actually creates a query parameter for parameter inside init __init__ function.
So for example, this is the model we used above.
class Location(BaseModel):
city: str
country: str
state: str
It becomes this with Depends.
class Location(BaseModel):
def __init__(self, city: str, country: str, state: str) -> None:
...
Then they will become query parameters. This is the OpenAPI schema for the /withdepends endpoint.
"parameters": [
{
"required":true,
"schema":{
"title":"City",
"type":"string"
},
"name":"city",
"in":"query"
},
{
"required":true,
"schema":{
"title":"Country",
"type":"string"
},
"name":"country",
"in":"query"
},
{
"required":true,
"schema":{
"title":"State",
"type":"string"
},
"name":"state",
"in":"query"
}
]
This is the OpenAPI schema it created for /withoutdepends endpoint.
"requestBody": {
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/Location"
}
}
},
"required":true
}
Conclusion
Instead of request body, you can create query parameters with the same model.
Pydantic models are very useful for the cases when you have +5 parameters. But it expects a request body by default. But OpenAPI specification doesn't allow request body in GET operations. As it says in the specification.
GET, DELETE and HEAD are no longer allowed to have request body because it does not have defined semantics as per RFC 7231.
So by using Depends you are able to create query parameters for your GET endpoint, with the same model.

How to build a Graqhql mutation with existing variables

This might seem like an odd question, or something really straightforward, but honestly I am struggling to figure out how to do this. I am working in Node.js and I want to set data I have saved on a node object into my GraphQL mutation.
I'm working with a vendor's GraqhQL API, so this isn't something I have created myself, nor do I have a schema file for it. I'm building a mutation that will insert a record into their application, and I can write out everything manually and use a tool like Postman to manually create a new record...the structure of the mutation is not my problem.
What I'm struggling to figure out is how to build the mutation with variables from my node object without just catting a bunch of strings together.
For example, this is what I'm trying to avoid:
class MyClass {
constructor() {
this.username = "my_username"
this.title = "Some Title"
}
}
const obj = new MyClass()
let query = "mutation {
createEntry( input: {
author: { username: \"" + obj.username + "\" }
title: \"" + obj.title + "\"
})
}"
I've noticed that there are a number of different node packages out there for working with Graphql, but none of their documentation that I've seen really addresses the above situation. I've been completely unsuccessful in my Googling attempts, can someone please point me in the right direction? Is there a package out there that's useful for just building queries without requiring a schema or trying to send them at the same time?
GraphQL services typically implement this spec when using HTTP as a transport. That means you can construct a POST request with four parameters:
query - A Document containing GraphQL Operations and Fragments to execute.
operationName - (Optional): The name of the Operation in the Document to execute.
variables - (Optional): Values for any Variables defined by the Operation.
extensions - (Optional): This entry is reserved for implementors to extend the protocol however they see fit.
You can use a Node-friendly version of fetch like cross-fetch, axios, request or any other library of your choice to make the actual HTTP request.
If you have dynamic values you want to substitute inside the query, you should utilize variables to do so. Variables are defined as part of your operation definition at the top of the document:
const query = `
mutation ($input: SomeInputObjectType!) {
createEntry(input: $input) {
# whatever other fields assuming the createEntry
# returns an object and not a scalar
}
}
`
Note that the type you use will depend on the type specified by the input argument -- replace SomeInputObjectType with the appropriate type name. If the vendor did not provide adequate documentation for their service, you should at least have access to a GraphiQL or GraphQL Playground instance where you can look up the argument's type. Otherwise, you can use any generic GraphQL client like Altair and view the schema that way.
Once you've constructed your query, make the request like this:
const variables = {
input: {
title: obj.title,
...
}
}
const response = await fetch(YOUR_GRAPHQL_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
})
const { data, errors } = await response.json()

how to use optional url parameters with NestjS

I'm trying to replace our current backend service using Nestjs library,
however, I want to create a route with 2 optional parameters in the URL something like :
/route/:param1/config/:OptionalParam3?/:OptionalParam3?
that means the route should catch :
route/aa/config
route/aa/config/bb
route/aa/config/bb/cc
how can I achieve that, I have tried to use ? and () but it's not working well.
If you are looking for how to annotate an optional query parameter, you can do it like so:
#ApiQuery({
name: "myParam",
type: String,
description: "A parameter. Optional",
required: false
})
async myEndpoint(
#Query("myParam") myParam?: string
): Promise<blah> {
[...]
}
Router params name should be unique. The correct route path is:
Existing one is:
/route/:param1/config/:OptionalParam3?/:OptionalParam3?
Correction:
/route/:param1/config/:OptionalParam3?/:OptionalParam4?
Opinion: You can use query params if the params are optional. It is never a good idea to create optional param routes (disagreements agreed). Both serve the same purpose, but having them as the query params makes it more understandable for debugging and fellow developers.
I solved this problem by using #Query decorator as below:
Here is my controller:
#Get()
async getAll(#Query('someParameter') someParameter?: number) {
return this.service.getAll(someParameter);
}
Here is my client (Angular) service:
getAll(someParameter?: number) {
return this.http.get(`apiUrl/controllerAddress?someParameter=${someParameter}`
);
}
You can use this structure:
-route
-aa
-config
-[[...id]].js
It will work for the routes :
route/aa/config/{anything}

Watson Conversation API says: 'Patterns are defined but type is not specified.'

I am trying to call the updateValue method of the Watson Conversation API using the Watson SDK for Node.js. The request updates the patterns of the patterns-type entity value.
My request fails with a 400 Bad Request and the message:
[ { message: 'Patterns are defined but type is not specified.',
path: '.patterns' } ],
Here is the code I'm using to call the API - pretty standard.:
let params = {
workspace_id: '<redacted>',
entity: 'myEntityType',
type: 'patterns', // tried with and without this line
value: 'myCanonicalValue',
new_patterns: ['test'],
};
watsonApi.updateValue(params, (error, response) => {
if (error) {
console.log('Error returned by Watson when updating an entity value.');
reject(error);
} else {
resolve(response);
}
});
Actually, what the request is doing is trying to delete a pattern from the pattern list. Since there is no endpoint for deleting patterns, I fetch the list of patterns, delete the one I need to delete from the pattern list, and send the now-reduced patterns list via the updateValue method. In the above example, imagine the pattern list was ['test', 'test2']. By calling updateValue with ['test'] only, we are deleting the test2 pattern.
I am using a previous API version but I've also tested it in the Assistant API Explorer and the version 2018-07-10 results in the same problem when sending a raw request body formed as follows:
{
"patterns": ["test"]
}
Am I doing something wrong or did I forget a parameter?
It's not a bug, but it is a non-intuitive parameter name. The service accepts a type parameter and the Node SDK has a wrapper parameter called new_type. If you are using this to update patterns and not synonyms (the default), then you need to specify new_type as "patterns" even though the parameter is listed as optional.
This appears to be a bug in Watson Conversation Node.js SDK.
To avoid this, always add new_type: 'patterns' to the params:
let params = {
workspace_id: '<redacted>',
entity: 'myEntityType',
new_type: 'patterns',
value: 'myCanonicalValue',
new_patterns: ['test'],
};
I read the Watson Assistant API for updateValue the following way:
The new_type parameter is not required, valid values are synonyms or patterns. However, if you don't provide that parameter, the default kicks in. According to the documentation the default is synonyms. This would explain the error when you pass in patterns.

Resources