getting error response for the Update api - node.js

I am new to this swagger and i created a small demo project in node-js to see how swagger will really works. I created 5 api's which 4 are working perfectly and when it comes to PUT api I am getting error ,but when i tried in postman it is working. Please look at the code below.
export let updateUser = async(req: Request, resp: Response) => {
try{
const use = await User.findById(req.params.id);
use.name = req.body.name;
// use.email = req.body.email;
const a1 = await use.save();
resp.json("successfully updated");
} catch(err) {
resp.send('Error')
}
}
this is the api which is calling above method in app.ts
//put-request
app.put('/user/update/:id',controller.updateUser);
This is the the swagger json of put API
"/user/update/{id}": {
"put": {
"tags": [
"Update-Api"
],
"summary": "Update-user",
"description": "To updatre the particular user",
"operationId": "updateUser",
"consumes": ["application/json"],
"parameters":[
{
"name":"Id",
"in":"path",
"description":"enter the id of the user",
"required":true,
"type":"string"
},
{
"name":"body",
"in":"body",
"description":"Enter the update value",
"required":true,
"$schema": {
"type": "#/definations/User"
}
}
],
"responses": {
"400": {
"description": "Invalid user supplied"
},
"404": {
"description": "User not found"
}
}
}
}

If you paste your API definition into https://editor.swagger.io, it will flag 2 syntax errors in the PUT operation. Make sure to fix these errors before testing your API.
In the parameter definition, change "name":"Id" to "name":"id" (lowercase id) to match the parameter letter case in the path template.
In the body parameter, change $schema to schema.

Related

uploading files - nodejs with typescript and tsoa and swagger

I build a web api with nodejs and express. I used tsoa to generate my routes and a swagger.json file.
I want to be able to upload files via the swagger landing page. I followed the instructions on this page: https://tsoa-community.github.io/docs/file-upload.html
My tsoa.json looks like this:
{
"entryFile": "src/app.ts",
"noImplicitAdditionalProperties": "throw-on-extras",
"controllerPathGlobs": [
"src/**/*.controller.ts"
],
"spec": {
"basePath" : "/",
"description": "",
"outputDirectory": "dist/api/public",
"specVersion": 3,
"specMerging": "recursive",
"paths": {
"/admin/commands/create": {
"post": {
"consumes": [
"multipart/form-data"
],
"parameters": [
{
"in": "formData",
"name": "randomFileIsHere",
"required": true,
"type": "file"
}
]
}
}
}
},
"routes": {
"routesDir": "src/api"
}
}
My controller:
#Tags("Admin Commands")
#Route("admin/commands")
export class AdminCommandController extends Controller
{
#Post('create')
public async CreateCommand(#Request() request: express.Request): Promise<void>
{
try{
await this.handleFile(request);
}
catch {
throw new Error("Error uploading file.");
}
console.log("No error");
}
private handleFile(request: express.Request): Promise<any> {
const multerSingle = multer().single("randomFileIsHere");
return new Promise((resolve, reject) => {
multerSingle(request, undefined, async (error: Error) => {
if (error) {
reject("error");
}
resolve("file will be in request.randomFileIsHere");
});
});
}
}
but when I use the tsoa swagger command to generate the the swagger.json the multipart/form-data is not added to my swagger.json. If I manually add the multipart/form-data to my swagger.json the input field on my swagger landing page is a text field instead of a file field.
"paths": {
"/admin/commands/create": {
"post": {
"operationId": "CreateCommand",
"consumes": [
"multipart/form-data"
],
"parameters": [
{
"in": "formData",
"name": "randomFileIsHere",
"required": true,
"type": "file"
}
],
"responses": {
"204": {
"description": "No content"
}
},
"tags": [
"Admin Commands"
],
"security": []
}
}
}
What am I missing or doing wrong? Furthermore, if this would work, how do i extract the file from the request. The documentation says the file will be added to the randomFileIsHere property of the request object, but if i call request.randomFileIsHere it will obviously throw an error.
I also tried to follow official documents. I was able to save the uploaded file, but codes didnt looked clean to me. Then I realised there is a #UploadedFile decorator. You can add it and read file directly.
#Post("profile-photo")
public async uploadProfilePhoto(#UploadedFile() profilePhoto) {
console.log(profilePhoto)
}
Using a HTTP testing tool ,like Postman, define a field named "profilePhoto" and select a file. You should be able to see it on server terminal.
I think that you can do something like that:
import fs from 'fs';
#Post("profile-photo")
public async uploadProfilePhoto(#UploadedFile('formInputNameForPhoto') profilePhoto) {
fs.writeFileSync('./photo', profilePhoto.buffer);
}
Here is the answer which helped me understand how can I save "ready" multer file object.

Getting an empty array on Axios GET request

I'm trying to do a GET request using Axios. The API's response includes several objects that are properly populated. However, one particular object/field is an array that always shows up as an empty array.
Here's the response I get (note the "users" object with the empty array):
{
url: 'https:/<removed>/customers/<removed>/users?number=41442268000',
users: [],
customer: {
url: 'https://<removed>/customers/<removed>',
id: '<removed>',
name: 'CX Customer1'
},
paging: { offset: 0, limit: 2000, count: 0 }
}
The strange thing is that it works perfectly fine when I use Postman to query the exact same resource:
{
"url": "https://<removed>/customers/<removed>/users?number=8013334001",
"users": [
{
"url": "https://<removed>/customers/<removed>/users/<removed>",
"id": "b1703d6a<removed>",
"bwId": "<removed>.webex.com",
"lastName": "One",
"firstName": "Gus1",
"displayName": "Gus1 One",
"type": "USER",
"callerIdLastName": "One",
"callerIdFirstName": "Gus1",
"callerIdNumber": "+1-8013334001",
"numbers": [
{
"external": "+1-8013334001",
"extension": "4001",
"primary": true
}
],
"location": {
"name": "Salt Lake City",
"id": "9a03e3e<removed>",
"url": "https://<removed>/customers/<removed>/locations/<removed>"
}
}
],
"customer": {
"url": "https://<removed>/customers/<removed>",
"id": "4c1ccbe<removed>",
"name": "CX Customer1"
},
"paging": {
"offset": 0,
"limit": 2000,
"count": 1
}
}
As observed in the above Postman response, the "users" array has an object inside of it.
Here's my Node.js code:
function getUsersByTN(customerInfo, userData) {
let rowNumber = 1;
let successCount = 0;
let failureCount = 0;
axios.defaults.headers.common["Authorization"] = `Bearer ${customerInfo.token}`;
console.log('Attempting to find users on Webex Calling using their phone number...');
return new Promise(async (resolve, reject) => {
try {
for (let data of userData) {
rowNumber++;
const phoneNumber = data.TN;
const getUserURL = `https://<removed>/customers/` +
`${customerInfo.customerId}/` +
`users?number=` +
`${phoneNumber}`;
const result = await axios.get(getUserURL);
console.log(result.data);
resolve(result);
}
}
catch (err) {
reject(new Error(err));
}
})
}
I have also tried to replace the async/await format with the more traditional way of using promises, but got the same result:
axios.get(getUserURL)
.then(result => console.log(result.data))
.catch(err => console.log(err));
What am I missing?
Thanks!
-Gus
I found the problem. My input CSV file had users with phone numbers that did not exist. As soon as I updated it with valid/existing phone numbers, it worked as expected.
The thing that threw me off is that the API still replies with a "200 OK" when I provide invalid phone numbers. I was expecting a "404 not found" for invalid numbers, so I didn't even think about checking the numbers.
My first thought was that this was a bug on the API. In other words, I initially thought that the API should reply with a "404 not found". However, as I thought more about this, I realized that a "200 OK" with an empty result is a more appropriate response. That's because a "404" would incorrectly indicate that the API resource could not be found, which would imply that the request was sent to an invalid URL. That's clearly not what we want. Instead, we want to let the application know that it reached a valid API resource, but that no results were found for the provided searched criteria.

No response returned and app gets down when requesting a sign in for Account Linking

Instantiating a SignIn using conv.ask() always fails. My action says no-response when sign-in flow is called and it leaves my app.
In my Firebase Functions log, the json below was spitted, which probably means that it is correctly called, but there is something wrong. I tried updating my Actions on Google console, cleared sign in setting in the Directory page, tested in some different accounts, cleared data to reset in my action app and as such. Needless to say, I set clientId inside the dialogflow class paramerter.
I totally have no idea for this. I have done many projects for Google Assistant apps which required SignIn Account Linking flow. But I encounter this strange behavior only for this project. What should I do? SDK verions is "actions-on-google": "^2.6.0".
Response {
"status": 200,
"headers": {
"content-type": "application/json;charset=utf-8"
},
"body": {
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.SIGN_IN",
"data": {
"#type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
"optContext": "For account creation"
}
},
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Please do sign in "
}
}
]
}
}
}
}
}
Inside conv.user 
{
"raw":{
"locale":"ja-JP",
"userId":"ABwppHGDYgpYn2waeaDyKoMZIqhg4ZxO56vXeAhs-43ZUC6VF3SdCvUGY3L1Vd08eTY_hRLfjrvp4"
},
"storage":{
},
"_id":"ABwppHGDYgpYn2waeaDyKoMZIqhg4ZxO56vXeAhs-43ZUC6VF3SdCvUGY3L1Vd08eTY_hRSfjrvp4",
"locale":"ja-JP",
"permissions":{
},
"last":{
},
"name":{
},
"entitlements":{
},
"access":{
},
"profile":{
}
}
// THIS SEEMS TO BE CALLED according to Firebase Functions Log
app.intent('StartSignIn', (conv) => {
conv.ask(new SignIn('For account creation'));
})
app.intent(INTENT.SignInIntent, (conv, params, signin) => {
console.log('INTENT.SignInIntent is called');
if (signin.status !== 'OK') {
conv.close(`failed`);
return;
}
conv.close('please wait');
});
UPDATE
I figured out the solution by making another folder and doing firebase init, and connected it to a new Firebase project. The main reason is unknown but it worked well by creating a new project.

Convert postman api call to Node.js call

I'm getting some troubles when trying to make a post request to an API made with swagger 2.0 (not by me).
I've imported a collection to postman, and when i perform a post request it works perfect. However in Node.js it outputs a 400 error with swagger library, and a 500 with axios.
Heres the schema that the collection provides in postman:
{
"workflowFunctionID": 1,
"workflowActionParameters": [
{
"name": "Description",
"value": "Probando y wea2",
"workflowFunctionParameterId": 2
},
{
"name": "Price",
"value": "25000",
"workflowFunctionParameterId": 3
}
]
}
As i mentioned it works perfectly. And this is the current code that am using Node.js:
main = async() => {
try {
const token = await acquireTokenWithClientCredentials(RESOURCE, CLIENT_APP_Id, CLIENT_SECRET, AUTHORITY);
const request = {
url: `${WORKBENCH_API_URL}/api/v1/contracts?workflowId=1&contractCodeId=1&connectionId=1`,
method: "POST",
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token.access_token}` },
body: {
workflowActionInput: {
workflowFunctionID: 1,
workflowActionParameters: [{
"name": "description",
"value": "cualkier wea"
},
{
"name": "price",
"value": "20000000"
}
]
}
}
}
let res = await Swagger.http(request);
console.log(res);
}
catch (err) {
console.error(err);
}
}
main();
How should i pass the body/form-data to the post request, or maybe using another package or code? Thanks in advance for any help.
When you have api running in postman, just see this button named "code" i marked with black
click on this button
select language as node.js
It will show you code in node.js for that api, just copy that code and paste where required.
Here i am attaching picture kindly see this

Botpress : How to reply with a dynamic multiple choice

I am trying to build a Botpress bot which gets replies for questions from backend. I am trying to inject a dynamic multiple choice question from backed as a reply to user. How can I do that? I couldn't find a way to do it in Botpress documentation or examples.
Can you try this inside your src/actions.js file? I was using Single Choice Option to respond to user.
getDataFromAPI: async (state, event) => {
const endPoint = 'https://api.github.com/repos'
try {
let response = await instance.get(`${endPoint}`)
console.log(response.data);
await event.reply('#builtin_single-choice', JSON.parse(response.data))
} catch (exception) {
console.log(exception);
await event.reply('#builtin_text', { text: `Failed to fetch data for this repo` })
}
}
Response from the API call should be in JSON with the below format
{
"text": "Offerings",
"choices": [
{
"title": "Standard",
"value": "standard"
},
{
"title": "Custom",
"value": "custom"
},
{
"title": "Enterprise",
"value": "enterprise"
}
],
"typing": true
}

Resources