I have data (JSON) in a file that I want to expose through an API. I know the data at build time but I don't know how to create static API routes or even expose the files through the API routes statically.
I googled two solutions for this:
Create a static page that returns a JSON file (couldn't find a solution, it always returned HTML).
Use the pages/api/[something] to generate the API (but it seems to always be dynamic).
My last resort is to try to access the file through the function on the /pages/api/[something].js but this is dynamic and not static.
The dynamic function that comes by default in /pages/api/hello.js folder:
export default (req, res) => {
res.statusCode = 200;
res.json({ name: "John Doe" });
};
What is the typical strategy here? I feel that I'm missing something.
FWIW, this is the dynamic way I found to generate the API dynamically:
// on file /pages/api/[article].js
import { getArticle } from "../../lib/api";
export default (req, res) => {
// It gets an article from a file, also can be used with getStaticProps
const article = getPost({article: req.article});
res.statusCode = 200;
// returns the JSON.
res.json(article);
}
I'd still prefer to have it static to not need any serverless functions running.
Use the pages/api/[something] to generate the API (but it seems to always be dynamic).
No it's not dynamic. From [something].js,if you export getStaticPath(this will generate static routes for you) and getStaticProps(this will inject the data to be served from corresponding routes), next build will have your static files generated, and ready to be served as api pages with raw json data.
Hope this had been what you were trying to solve.
Related
I am using node js , express. I am trying to call a function in template literal.
I made a module and import in main file and then add the function to app.locals and accessing in my views that works fine. But when i try to use it in template literals and also in my public file it give me error "currencyToWords is not defined".
I think in public file it makes sense because i make public folder static.
but in my views it is weird because when i use it in html it works but when i use it in template literal it gives error.
I want to use the currencyToWords function in template literals to change the response.
I have one solution that i can make the file in public folder and add the function in script in that file and import in footer but i dont want to do that.
Can anybody help me in solving the issue.
My app stucture
module.exports = { currencyConverter }
In app.js
app.js is my main file where i create server
var { currencyToWords } = require('./config/functions');
app.locals.currencyToWords = currencyToWords;
by adding in locals i can access it in my application any where
This code is working:
<div class="fix pull_right">
<h3><%= currencyToWords(property.propertyDetails.price)%></h3>
</div>
This is not working
var a =`
<p>${currencyToWords(property.propertyDetails.price)}</p>
`;
the above code is same but only difference is first one is use in ejs tags and second in ejs and template literals.
Here is the documentation from express about app.locals
app.locals
The app.locals object has properties that are local variables within the application.
console.dir(app.locals.title)
// => 'My App'
console.dir(app.locals.email)
// => 'me#myapp.com'
Once set, the value of app.locals properties persist throughout the life of the application, in contrast with res.locals properties that are valid only for the lifetime of the request.
You can access local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data. Local variables are available in middleware via req.app.locals (see req.app)
app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = 'me#myapp.com'
I'm working on a React frontend that gets data from a python JSON API. One section of my website has premium content and is reserved for paying users; currently I ensure that other users don't have access to it by fetching the content as a JSON object and converting it to JSX on the frontend according to a certain convention. For example:
{
{ 'type': 'paragraph', 'value': 'some text'},
{ 'type': 'anchor', 'href': 'some url', 'value': 'some description'}
}
would be rendered as :
<p>some text</p>
some description
Not surprisingly, things started to get pretty complicated as the content began to get more structured, simple things like making part of the text bold require a disproportional amount of effort.
As a potential solution, I had this idea: instead of sending the content as an object and parsing it, why not send a string of JSX and evaluate it on the frontend?
I started like this:
import * as babel from "#babel/standalone";
export function renderFromString(code) {
const transformed_code = babel.transform(code, {
plugins: ["transform-react-jsx"]
}).code;
return eval(transformed_code);
}
I imported this function in my premiumContent page and tried passing a complete component as a string (with import statements, etc) but got errors because the modules can't be found. I assumed this happens because the code is being interpreted by the browser so it doesn't have access to node_modules?
As a workaround, I tried passing only the tags to renderFromString and call it in the context of my component where all the modules are already imported :
import * as babel from "#babel/standalone";
export function renderFromString(code, context) {
const _es5_code = babel.transform(code, {
plugins: ["transform-react-jsx"]
}).code;
return function() {
return eval(_es5_code);
}.call(context);
}
This also failed, because it seems that eval will still run from the local context.
Finally, I tried doing the same as above but executing eval directly in my component, instead of from my function .This works as a long as I store "React" in a variable : import ReactModule from "react";const React = ReactModule, otherwise it can't be found.
My questions are:
Is there any way I can make my first two approaches work?
I know eval is considered harmful, but since the content is always completely static and comes from my own server, I don't see how this wouldn't be safe. Am I wrong?
Is there a better solution for my problem? That is, a way to safely deliver structured content to only some users without changing my single page app + JSON api setup?
The best solution for this is React server-side rendering.
Since you need markup that is client-side compatible but at the same time dynamically generated through React, you can offload the markup generation to the server. The server would then send the rendered HTML to the client for immediate display.
Here's a good article about React SSR and how it can benefit performance.
I am working on an angular application with the angular cli. Right now I am using http.get to call a local json file and render the data on initial load. My task is after a certain amount of time of initial load, I am supposed to call data from a different local json file and update the UI to reflect the new data. I am unsure of the best way to approach this. Can someone provide some examples of a data refresh?
You can use the setTimeout function.
e.g.
setTimeout(() => {
// Load from the other json file
}, 1000);
Let's say, you want to use a json file that contains a list of cities and you want to reference the city names in a dropdown list, this is how you will go about it.
Since you are using the Angular Cli, that means you are using Webpack so first of all, go to typings.d.ts and insert an object like this.
declare module "*.json" {
const value: any;
export default value;
}
The above code will allow you to import your json file in your component.
Now go to your component and import your json file. For example:
import * as cities from "./cities.json"
Next, you can use this little hack to get the contents of the json file.
cities: any = cities
Now in your view, you can reference it in let's say an ngFor
<select>
<option *ngFor='let city of cities'>{{city.name}}</option>
</select>
Try something like this:
file1$ = this.http.get('file1.json');
file2$ = this.http.get('file2.json').delay(1000);
Observable.combineLatest(file1$, file2$)
.subscribe(([file1, file2]) => { ... })
If your json files are only local you can also import them directly. Add typings.d.ts file in your project root with:
declare module '*.json' {
const value: any;
export default value;
}
Then you can use it in your code:
import * as file1 from './file1.json';
Does app.js get processed only once?. In that case, does it make sense to run setup queries in app.js so that I don't have to run it on every request?.
I have a table to countries and regions that I need in several requests.
I am looking at an implementation something like this https://stackoverflow.com/a/21133217/406659
No putting this in app.js does not make sense. I would create a models folder and encapsulate all of your database logic in a module within that folder. Then on startup of the app (ie on app.listen() callback) I would call a method from that module which does the setup for me. For example:
Some DB module in models
module.exports = {
setup: () => {
// Set up logic here - checking if tables exist etc
}
}
Then in app.js or equal
require <SOME DB MODULE>
app.listen(<PORT>, () => {
<SOME DB MODULE>.setup();
})
Note this is a generalised approach as I don't know the specifics of your setup - This approach just ensures encapsulated and reusable code. I've also used ES6 syntax where possible.
Hope this helps
Dylan
I'm just getting started with express.js and am failing to understand how one defines discrete "pages" (in the traditional sense) that one can link to internally.
I'm using Jade as a template engine and I see how it pulls the various components together and references them in the app.js (which is what is initially invoked by npm) so that, in effect is my "index". Would be great to see a tutorial on what one does to then build out pageA, pageB, pageC so that they can be linked to via <a href="pageA.html"> (or the Jade equivalent).
I'm assuming this is possible, right?
Express.js itself does not offer URL generation, only a built-in router.
You would need to use an additional package to perform URL generation, or build it yourself. Maybe you find something fitting in this question's answers: URL generation for routes in express
If you do not care about route generation and want to "hard code" the URLs, you would need to add a route for each static page, like this:
// routes.js
app.get("/pageA.html", function(req, res, next) { res.render("static/page_a", { templateLocals: "here" }) };
app.get("/pageB.html", function(req, res, next) { res.render("static/page_b") };
Or, if you have many of those pages, you could use a controller for this:
// static_page_controller.js
module.exports = function(pageTemplate) {
return function(req, res, next) {
return res.render("static/" + pageTemplate);
}
}
And use it like this:
// routes.js
var staticController = require("./static_page_controller");
app.get("/pageA.html", staticController("page_a"));