Custom routes in json-server using Node.js - json

I found problem when using custom routes for requesting db.json which is deployed in json-server.
For example for this given json as below, I'd like to access voters by name, so when I type this
url:
https://localhost:3000/data/1/sessions/:sessionId/voters/:voterName
Where are sessionId and voterName are parameterized, the response should be {"voterName"}
db.json:
{
"id": 1,
"name": "Angular Connect",
"date": "2036-09-25T23:00:00.000Z",
"time": "10:00 am",
"price": 599.99,
"imageUrl": "/assets/images/angularconnect-shield.png",
"location": {
"address": "1057 DT",
"city": "London",
"country": "England"
},
"sessions": [
{
"id": 1,
"name": "Using Angular 4 Pipes",
"presenter": "Peter Bacon Darwin",
"duration": 1,
"level": "Intermediate",
"abstract": "Learn all about the new pipes in Angular 4, both \n how to write them, and how to get the new AI CLI to write \n them for you. Given by the famous PBD, president of Angular \n University (formerly Oxford University)",
"voters": [
"bradgreen",
"igorminar",
"martinfowler"
]
},
{
"id": 2,
"name": "Getting the most out of your dev team",
"presenter": "Jeff Cross",
"duration": 1,
"level": "Intermediate",
"abstract": "We all know that our dev teams work hard, but with \n the right management they can be even more productive, without \n overworking them. In this session I'll show you how to get the \n best results from the talent you already have on staff.",
"voters": [
"johnpapa",
"bradgreen",
"igorminar",
"martinfowler"
]
},
{
"id": 3,
"name": "Angular 4 Performance Metrics",
"presenter": "Rob Wormald",
"duration": 2,
"level": "Advanced",
"abstract": "Angular 4 Performance is hot. In this session, we'll see \n how Angular gets such great performance by preloading data on \n your users devices before they even hit your site using the \n new predictive algorithms and thought reading software \n built into Angular 4.",
"voters": []
},
{
"id": 4,
"name": "Angular 5 Look Ahead",
"presenter": "Brad Green",
"duration": 2,
"level": "Advanced",
"abstract": "Even though Angular 5 is still 6 years away, we all want \n to know all about it so that we can spend endless hours in meetings \n debating if we should use Angular 4 or not. This talk will look at \n Angular 6 even though no code has yet been written for it. We'll \n look at what it might do, and how to convince your manager to \n hold off on any new apps until it's released",
"voters": []
},
{
"id": 5,
"name": "Basics of Angular 4",
"presenter": "John Papa",
"duration": 2,
"level": "Beginner",
"abstract": "It's time to learn the basics of Angular 4. This talk \n will give you everything you need to know about Angular 4 to \n get started with it today and be building UI's for your self \n driving cars and butler-bots in no time.",
"voters": [
"bradgreen",
"igorminar"
]
}
]
}
For showing the last result I used custom routes in NodeJS like below:
router.js:
var jsonServer = require('json-server')
const low = require('lowdb')
var server = jsonServer.create()
const db = low('db.json')
// Add custom routes before JSON Server router
server.get('/data/:id/sessions/:sessionId/voters/:voterName', function (req, res) {
// See https://github.com/typicode/lowdb
var user=db.get("sessions")
.find({id:sessionId})
.get("voters")
.find({voterName})
.value()
if (user) {
res.jsonp(user)
} else {
res.sendStatus(404)
}
})
server.use(function (req, res, next) {
if (req.method === 'POST') {
req.body.createdAt = Date.now()
}
// Continue to JSON Server router
next()
})
// Use default router
// server.use(router)
server.listen(3000, function () {
console.log('JSON Server is running')
})
But when I run this command:
json-server --watch db.json --middlewares router.js
I get the following error:
TypeError: app.use() requires a middleware function
at Function.use (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\application.js:210:11)
at createApp (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\run.js:79:9)
at load (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\run.js:148:13)
at module.exports (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\utils\load.js:37:5)
at start (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\run.js:125:5)
at module.exports (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\run.js:162:3)
at module.exports (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\index.js:81:3)
at Object.<anonymous> (C:\Users\maoutir\AppData\Roaming\npm\node_modules\json-server\lib\cli\bin.js:3:14)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
Thanks in advance for your answer.

I think you should not use the --middlewares options to start your server, router.js is not a middleware. so here it try to add your router.js as a middleware and fail to start
could you try :
json-server router.js --watch db.json

There are two options to use json server one is running it through your own js file the other is through running the middle wares you are running the js file you should be running middlewares as such https://github.com/typicode/json-server#add-middlewares only create the module.export as shown in the link. You don't need all the fancy server stuff.

Related

Can my bot server retrieve any information in the app manifest?

I am adding a new static tab to an existing teams app.
One of the new features is that the chat will publish a deep link to the static tab. This is creating a dilemna when I am contemplating deployment.
Obviously I can’t put my entire application up here, but we can assume a situation like this:
The manifest I have in production that is in the App Store looks like this:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.9/MicrosoftTeams.schema.json",
"manifestVersion": "1.9",
"version": "2.0.1",
"id": "23232322-7676-4848-5555-44444444444",
"packageName": "xxxxx",
"developer": {
"name": "xxxxx",
"websiteUrl": "https://www.xxxx.com/",
"privacyUrl": "https://www.xxxx.com/legal/privacy",
"termsOfUseUrl": "https://www.xxxxx.com/legal/privacy"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "abra",
"full": "abra cadabra"
},
"description": {
"short": "short",
"full": "full"
},
"accentColor": "#FFFFFF",
"bots": [
{
"botId": "11111111-2222-3333-4444-555555555555",
"scopes": [
"personal"
],
"commandLists": [
{
"scopes": [
"personal"
],
"commands": [
{
"title": "Test",
"description": "Test"
}
]
}
],
"supportsFiles": false,
"isNotificationOnly": false
}
],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": [
"token.botframework.com",
"teams.microsoft.com",
"*.ngroc.io"
]
}
And in my bot in response to the “Test” command I return a simple text message, i.e.
return await step.prompt('textPrompt', { prompt: 'In the next version we will have a test tab' })
Now in development, I have added the following section to the manifest (after “bots”)
"staticTabs": [
{
"entityId": "conversations",
"scopes": [
"personal"
]
},
{
"entityId": "testtab”,
"contentBotId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"name": “Go To Test Tab",
"scopes": [ "personal" ]
},
{
"entityId": "about",
"scopes": [
"personal"
]
}
],
And I have updated the value of the version from 2.0.1 to 2.1.0
Now, in response to the “Test” message I am returning an adaptiveCard that looks like this:
{
type: 'AdaptiveCard',
version: '1.3',
body: [],
actions: [
{
type: 'Action.OpenUrl',
title: 'Go To Test Tab',
url: ‘https://teams.microsoft.com/l/entity/23232322-7676-4848-5555-44444444444/testtab’
}
]
}
This works very nicely and when I press the “go to Test Tab” it opens up the test tab as desired.
My problem is with deploying.
If I submit my new manifest to the App Store, without updating my production server, those testing the new version will continue to get the message “In the next version we will have a test tab” and be missing the link to the new tab.
If I update my production server now, before the update in the App Store, my current users will get the adaptive card with the button that will fail if they press it.
Clearly, neither of these options are good.
Ideally, my response should be something like:
If tabExists() {
Return {… the adaptive card }
Else {
return await step.prompt('textPrompt', { prompt: 'In the next version we will have a ‘test tab })
}
However, I don't know how to write "tabExists()" - I was thinking maybe there was some way to access the version number from the bot manifest, or the list of static tabs, and use that information, but I am happy for alternative suggestions.
We can get the manifest version using below Graph API or using SDK method:
https://learn.microsoft.com/en-us/graph/api/appcatalogs-list-teamsapps?view=graph-rest-1.0&tabs=http#example-4-list-applications-with-a-given-id-and-return-the-submission-review-state
So, before sending the Adaptive Card or message, you can put a custom condition to check the manifest version and send the message accordingly.
You can check the manifest version as explained by Chetan, i tried the same and figured its actually not the best idea.
It always should be best practice to have a "production" and "test" server or something like that.
Having different manifest versions point to the same server and running checks which version you're on will more than likely lead to issues sooner or later.
I sometimes even have 3 different instances running (prod, staging, test) to try various builds and things.
You can check that in your code but imo its not advisable to do so.

Import JSON file in React with data format error

I tried to import a JSON file in my React project, but got the parsing error:
json file:testData.json
{
"data": {
"articles": [
{
"id": "95c12a8f6c88953ca8f8a39da25546e6",
"title": "Introducing React's Error Code System",
"date": "Mon Jul 11 2016 00:00:00 GMT+0000 (UTC)",
"authorId": "2c6aa2cfe3449467d329fa17d6ea230f",
"body": "Building a better developer experience has been one of the things that React deeply cares about, and a crucial part of it is to detect anti-patterns/potential errors early and provide helpful error messages when things (may) go wrong. However, most of these only exist in development mode; in production, we avoid having extra expensive assertions and sending down full error messages in order to reduce the number of bytes sent over the wire."
}
],
"authors": [
{
"id": "d85577ea34ae50f2dac5347b5219aa23",
"firstName": "Andrew",
"lastName": "Clark",
"website": "https://twitter.com/acdlite"
}
]
}
}
DataApi.js file:
export default class DataApi {
// property: rawData
constructor(rawData) {
this.rawData = rawData;
}
mapIntoObject(arr) {
return arr.reduce((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
}
getArticle() {
return this.mapIntoObject(this.rawData.articles);
}
getAuthors() {
return this.mapIntoObject(this.rawData.authors);
}
}
And I tried to import JSON data in this file:
import DataApi from "./DataApi"; // object to process data
import { data } from "./testData.json"; // raw data
// create a api object to host raw data
let api = new DataApi(data);
const articles = api.getArticle();
console.log(articles);
then I got the error:(the import directory are correct):
2:13 error Parsing error: Unexpected token, expected ";"
1 | {
> 2 | "articles": [
| ^
3 | {
4 | "id": "95c12a8f6c88953ca8f8a39da25546e6",
5 | "title": "Introducing React's Error Code System",
What is the problem?
You can do export default
testData.json:
const data = {
"data": {
"articles": [
{
"id": "95c12a8f6c88953ca8f8a39da25546e6",
"title": "Introducing React's Error Code System",
"date": "Mon Jul 11 2016 00:00:00 GMT+0000 (UTC)",
"authorId": "2c6aa2cfe3449467d329fa17d6ea230f",
"body": "Building a better developer experience has been one of the things that React deeply cares about, and a crucial part of it is to detect anti-patterns/potential errors early and provide helpful error messages when things (may) go wrong. However, most of these only exist in development mode; in production, we avoid having extra expensive assertions and sending down full error messages in order to reduce the number of bytes sent over the wire."
}
],
"authors": [
{
"id": "d85577ea34ae50f2dac5347b5219aa23",
"firstName": "Andrew",
"lastName": "Clark",
"website": "https://twitter.com/acdlite"
}
]
}
}
export default data;
and while importing
With json-loader installed, you can use
import data from "./testData.json";
or If you have used create-react-app to scaffold your project, the module is already included, you just need to import your json:
import data from "./testData";
To install json-loader
npm install --save-dev json-loader
And add below config to your webpack.config.js
webpack.config.js
module.exports = {
module: {
loaders: [
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
}
You have to export your json data, your json data should be like this.
export const data = {
"data": {
"articles": [
{
"id": "95c12a8f6c88953ca8f8a39da25546e6",
"title": "Introducing React's Error Code System",
"date": "Mon Jul 11 2016 00:00:00 GMT+0000 (UTC)",
"authorId": "2c6aa2cfe3449467d329fa17d6ea230f",
"body": "Building a better developer experience has been one of the things that React deeply cares about, and a crucial part of it is to detect anti-patterns/potential errors early and provide helpful error messages when things (may) go wrong. However, most of these only exist in development mode; in production, we avoid having extra expensive assertions and sending down full error messages in order to reduce the number of bytes sent over the wire."
}
],
"authors": [
{
"id": "d85577ea34ae50f2dac5347b5219aa23",
"firstName": "Andrew",
"lastName": "Clark",
"website": "https://twitter.com/acdlite"
}
]
}
}
change .json to .js extention, while importing
import { data } from "./testData"; // raw data

Angular 6 - Unexpected token in JSON at position 0

My Angular 5 project was working without issues, just after having updated it to version 6, it stopped building using ng build due to the next:
ERROR in ./src/app/assets/i18/en.json Module parse failed: Unexpected
token in JSON at position 0 You may need an appropriate loader to
handle this file type.
here is my json file:
{
"app": {
"Welcome": "Welcome",
"New": "New"
},
"mainMenu": {
"Home": "Home",
"Logout": "Logout"
},
"pageHeader": {
"About": "About",
"Settings": "Settings"
}
}
Most solutions on the web are talking about CopyWebpackPlugin but the project doesn't use any Webpack configuration file.
then, following this link I tried to make the json as an array:
{
"menu":[
"app": {
"Welcome": "Welcome",
"New": "New"
},
"mainMenu": {
"Home": "Home",
"Logout": "Logout"
},
"pageHeader": {
"About": "About",
"Settings": "Settings"
}
]
}
But got the following error, despite the file contains 16 lines.
Unexpected token : in JSON at position 24
Any idea ?
Inspired by #AndrewJuniorHoward, found that while upgrade process, all the json files were encoded to UTF-8-BOM instead of UTF-8, that's why Angular was unable to load them during build.
In Visual Studio code, I just created empty files, pasted in them the content of the old json files and then overwritten them, and all worked perfectly.
Resave the angular.json file as UTF8. There seems to be a recent problem with upgrading to Angular 6 regarding this.
Hope you have resolved the issue but still if you want some minor changes you can try adding "id" to objects in array as below, I Tried this in my CLI project on Angular 6 while performing CURD operation in JSON file.
{
"menu":[
"app": {
"id": 1,
"Welcome": "Welcome",
"New": "New"
},
"mainMenu": {
"id": 2,
"Home": "Home",
"Logout": "Logout"
},
"pageHeader": {
"id": 3,
"About": "About",
"Settings": "Settings"
}
]
}

How to 'run' an IVR saved in JSON?

I am working on a IVR solution for small businesses in my local area but I am having trouble wrapping my head around how Node will handle menus. I could make a seperate Node server for each of my customers but I would like to have a single server that pulls each customer's IVR setup from a Mongo database or file when their number is called. I have an idea on how to save the menu structure in JSON but I am lost when it comes to turning that JSON into responses to <gather> inputs. I was thinking I could use a JSON structure like this in the DB (or maybe as a .json file on Amazon S3):
{
"menu": {
"id": 1,
"name": "Main",
"script": "Thank you for calling Local Company. To speak to sales press 1, ...",
"options": [
{
"name": "",
"action": "",
"value": "",
"next": ""
},
{
"name": "Sales",
"action": "dial",
"value": 12345678901,
"next": ""
},
{
"name": "Support",
"action": "dial",
"value": 12345678902,
"next": ""
},
{
"name": "Directions",
"action": "say",
"value": "Our offices are located at...",
"next": 1
},
{
"name": "Mailbox",
"action": "mailbox",
"value": "main",
"next": 1
}
]
}
}
Twilio developer evangelist here.
If you can return the JSON based on the number a user is dialling, then you could do something like this:
const Twilio = require('twilio');
app.post('/voice', (req, res) => {
const dialledNumber = req.body.To;
getIVRObjectFromPhoneNumber(dialledNumber, (IVRObject) => {
const twiml = Twilio.twiml.VoiceResponse();
if (typeof req.body.Digits !== 'undefined') {
// A user has pressed a digit, do the next thing!
const action = IVRObject.menu.options[req.body.Digits]
twiml[action.action](action.value);
} else {
// No digits yet, return the <Gather>
const gather = twiml.gather({
numDigits: 1
});
gather.say(IVRObject.script);
}
res.send(twiml.toString());
});
});
This doesn't quite use all of your object, I'm not sure what the values for next mean, but hopefully it's a start. The getIVRObjectFromPhoneNumber method is my made up, asynchronous method that returns a JavaScript object parsed from your example JSON above.
Let me know if this helps at all.

Include root in django rest framework responses

I have a ready Django project that serves JSON via the rest_framework and its viewsets. Now I would like to write the client using Ember. Here is my setup:
Django 1.6.5
Ember 1.6.1
Ember-Data 1.0.0-beta.8.2a68c63a
jQuery 2.1.1
My Django server runs on the default port 8000 under localhost. I test my Ember application by opening index.html in the browser. Therefore, I customised the ApplicationAdapter like so
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:8000',
});
I try to fetch a list of artists from http://localhost:8000/artists. The specified route is
App.ArtistsRoute = Ember.Route.extend({
model: function() {
this.store.find('artists');
}
});
And the response I get back from the server when I open the mentioned url in the browser is
[
{
"id": 1,
"name": "Kollegah",
"origin": "Germany",
"genre": "German Rap"
},
{
"id": 2,
"name": "Peter Fox",
"origin": "Germany",
"genre": "Hip-Hop"
},
{
"id": 3,
"name": "Farid Bang",
"origin": "Germany",
"genre": "German Rap"
},
{
"id": 4,
"name": "Eko Fresh",
"origin": "Germany",
"genre": "German Rap"
}
]
When fetching the data I these two Ember errors:
-Error while processing route: artists No model was found for 'artists' Error: No model was found for 'artists'
-No model was found for 'artists' Error: No model was found for 'artists'
The problem is that I have specified a model already
var attr = DS.attr;
App.Artist = DS.Model.extend({
name: attr,
origin: attr,
genre: attr,
});
I suppose the problem is the missing root element at the beginning of each JSON response. I suggest it should look like this example from the Ember Guides:
{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": ["1", "2"],
"user" : "dhh"
},
"comments": [{
"id": "1",
"body": "Rails is unagi"
}, {
"id": "2",
"body": "Omakase O_o"
}]
}
After searching a short while I found a similar problems with Rails. I tried out the solution for Django mentioned in another Stackoverflow question but I got the same errors.
Does anybody know a server-side solution for this problem? The Ember Data Django Adapter could be one for the client side. Unfortunately, it is designed as a node plugin and at the moment I don't use it for my project.
The Ember Data Django Adapter is the most simple way of solving your problem, and if you pay attention to the docs, there are instructions for using it without ember-cli.