backendstack21 / restana Goto Github PK
View Code? Open in Web Editor NEWRestana is a lightweight and fast Node.js framework for building RESTful APIs.
License: MIT License
Restana is a lightweight and fast Node.js framework for building RESTful APIs.
License: MIT License
Disclaimer: I'm the author of Anumargak package.
I would like you to have a look on anumargak router which may increase the speed of restana. Here is the comparison;
Anumargak supports some additional features.
🚨 You need to enable Continuous Integration on all branches of this repository. 🚨
To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.
Since we didn’t receive a CI status on the greenkeeper/initial
branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.
If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/
.
Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial
branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.
Hello,
What is the best way to have a middleware wait for the response after the removal of the response event? Do i need to use express middlewares such as onHeaders like the response-time module does?
Thanks!
I was wondering if you ever came across https://github.com/uNetworking/uWebSockets.js
Using it could drastically improve Ana's performance.
Is there a way to delete a route?
Hi! 👋Very nice work creating this framework!
I just wanna ask, what is the reason behind errClass
reply prop inside error handler?
I am using your framework but it seems like I cannot get to the errorHandler
function.
const service = require('restana')({
errorHandler (err, req, res) {
console.log(`Unexpected error: ${err.message}`)
res.send(err)
}
});
const config = require('./config');
const bodyParser = require('body-parser');
service.use(bodyParser.json());
service.use(
bodyParser.urlencoded({
extended: true,
}),
);
const compression = require('compression');
service.use(compression());
const cors = require('cors');
service.use(cors());
service.use(async (req, res, next) => {
try {
await next()
} catch (err) {
return next(err)
}
})
// Register controllers
const glob = require('glob');
const controllers = glob.sync(`${config.rootDir}/controllers/*.js`);
controllers.forEach((controller) => {
require(controller)(service);
});
const primaryDb = require('./db/primary');
primaryDb.sequelizeInstance
.sync({ alter: true })
.then((syncResult) => {
console.log('Database syncronized', syncResult);
return service.start(config.portNumber);
})
.then((server) => {
console.log('Server Started', server);
})
.catch((error) => {
console.error('Server failed to start', error);
});
const router = service.getRouter();
const Services = require('../services');
router.get('/keys', (request, response, next) => {
new Services.PublicFrontEndService()
.GetAllKeys()
.then((result) => {
response.send(result);
})
.catch((error) => {
next(error);
});
});
router.get('/keys/:key', async (request, response, next) => {
try {
const result = await new Services.PublicFrontEndService().GetByKey(request.params.key);
response.send(result);
} catch (error) {
next(error);
}
});
module.exports = (app) => app.use('/api/public/fe/v1', router);```
The treatment of files is too important, it would only be enough to do a .pipe and that's it, but there are more things that should be taken into consideration, such as adding the correct Content-Type header depending on the file format, as well as the Range header of the request , it is also important that there is a parameter to control the Content-Disposition and make it downloadable or not.
Is your feature request related to a problem? Please describe.
Hey there! I was lurking through the restana source codes (again) looking for ways to optimise it further, but stumbled upon a comment in response-extensions.js: // ToDo: fast json stringify ?
. I do not currently use fast-json-stringify, so I might be biased regarding its importance, but I think this is something to be debated about by those who use restana?
Problems with including fast-json-stringify
The problem with fast-json-stringify is that it requires a schema. Without a proper schema, it errors out or produces {}
string. However, the current res.send API does not leave any possibility to pass the schema in any convenient manner. I have tried to compile some possible options there could be.
Possible alternatives
Including a separate res.send alternative in restana core just for the purpose of fast-json-stringify. Something like res.fastJson
Pros: 1) solves the API problem; 2) no unnecessary checks
Cons: 1) software bloat; 2) additional dependency; 3) violates the restana philosophy
Allow to pass schema as res.fastJsonSchema (defaulting to null), which will be passed to stringify function.
It could then look like this:
const stringify = (obj, schema) => {
if (schema) {
return fastJson(schema)(obj)
}
return JSON.stringify(obj)
}
Pros: avoids the API problem
Cons: 1) additional dependency; 2) additional check with every res.send response with a proper object, which will decrease the op/s count; 3) violates the restana philosophy
Leave the issue to the restana users. Those who need fast-json-stringify should be perfectly capable of using it themselves, without any sugar in restana. However, the comment in question should be deleted to avoid future confusion.
Pros: 1) API problem? What problem? 2) most compatible with restana philosophy
Cons: none?
If i throw an error on async function crash the server.
app.post('/auth/google', async (req: any, res: any) => {
throw new Error('Invalid google login');
return;
});
Hi,
I do not understand where the errors are caught when using swagger middlewares.
In the code below neither HANDLER 1 nor HANDLER 2 are called when a route throws an error.
Request is stuck and eventually failed with a timeout client-side.
Swagger-tools doc is not very helpful...
const path = require('path')
const service = require('restana')({
errorHandler (err, req, res) {
// HANDLER 1
console.log(`Unexpected error: ${err.message}`)
res.send(err)
}
})
const swagger = require('swagger-tools')
const spec = require('./swagger.json')
swagger.initializeMiddleware(spec, async (middleware) => {
service.use(middleware.swaggerMetadata())
service.use(middleware.swaggerValidator())
service.use(middleware.swaggerUi())
service.use(middleware.swaggerRouter({
controllers: path.join(__dirname, '/controllers')
}))
service.use(async (req, res, next) => {
// HANDLER 2
try {
await next()
} catch (err) {
console.log('upps, something just happened')
res.send(err)
}
})
await service.start(4000)
console.log('API documentation is now running at http://localhost:4000/docs/')
})
This my code in server side
const service = require('restana')({
disableResponseEvent: true
})
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser')
const parseForm = bodyParser.urlencoded({extended:false})
const csrf = require('csurf')
const csrfProtection = csrf({cookie: true})
//const invalid = require('./middlewares/invalidCsrf')
const cors = require('cors')
service.use(cookieParser())
service.use(cors({
credentials: true,
origin: true,
}))
service.use(bodyParser.json())
service.use(csrfProtection)
service.get('/form_login', (req, res) => {
res.send({csrfToken: req.csrfToken()})
})
service.post('/process_login',parseForm, (req, res)=>{
console.log(req)
res.send({message: 'THIS IS GREAT'})
})
service.start(3000).then(() => console.log('USER service listening on 3000 port!'))
This my code in client side
import React, {useState, useContext, useEffect} from 'react';
import {Link, useHistory} from 'react-router-dom'
import M from 'materialize-css'
import axios from 'axios';
const Signin = ()=>{
const [password, setPassword] = useState("")
const [email, setEmail] = useState("")
const [_csrf, set_Csrf] = useState("")
useEffect(()=>{
axios.get('http://localhost:3000/form_login', {
})
.then( (response) => {
console.log(response.data.csrfToken)
set_Csrf(response.data.csrfToken)
})
.catch( (error) => {
console.log(error);
});
// fetch("http://localhost:8080/service/form_login",{
// method:"get",
// //credentials: 'include',
// headers:{
// "Content-Type":"application/json",
// },
// }).then(res=>res.json())
// .then(response=>{
// set_Csrf(response.data.csrfToken)
// }).catch(err=>{
// console.log(err)
// })
},[])
const PostData = async()=>{
if(!/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email)){
M.toast({html: "email tidak valid",classes:"#c62828 red darken-3"})
return
}
//console.log(_csrf)
//return;
await fetch("http://localhost:3000/process_login",{
credentials: 'same-origin',
headers:{
"Content-Type":"application/json",
// "x-csrftoken": _csrf,
// "x-csrf-token": _csrf,
// "xsrf-token": _csrf,
// "csrf-token": _csrf,
"X-XSRF-TOKEN": _csrf
},
method:"POST",
body:JSON.stringify({
password,
email,
_csrf
})
}).then(res=>res.json())
.then(data=>{
console.log("data: "+data.message)
if(data.error){
M.toast({html: data.error,classes:"#c62828 red darken-3"})
}else{
//localStorage.setItem("jwt",data.token)
//localStorage.setItem("user",JSON.stringify(data.user))
// dispatch({type:"USER",payload:data.user})
// M.toast({html:"signedin success",classes:"#43a047 green darken-1"})
// history.push('/')
}
}).catch(err=>{
console.log(err)
})
// const data = {
// email: email,
// password: password,
// csrfToken: _csrf
// }
// await axios.post('http://localhost:8080/service/process_login', {
// data,
// headers:{
// "Content-Type":"application/json",
// "x-csrftoken": _csrf,
// "CSRF-Token": _csrf
// },
// })
// .then( (response) => {
// console.log(response.data.csrfToken)
// set_Csrf(response.data.csrfToken)
// })
// .catch( (error) => {
// console.log(error);
// });
}
return (
<div className="mycard">
<div className="card auth-card input-field">
<h2>InstaStock</h2>
<input
type="text"
value={_csrf}
onChange={(e)=>set_Csrf(e.target.value)}
/>
<input
type="text"
placeholder="email"
value = {email}
onChange={(e)=>setEmail(e.target.value)}
/>
<input
type="password"
placeholder="password"
value = {password}
onChange={(e)=>setPassword(e.target.value)}
/>
<button className="btn waves-effect waves-light #42a5f5 blue lighten-1"
onClick={()=>PostData()}
>
Login
</button>
<h5>
<Link to="/signup">Dont have an account ?</Link>
</h5>
<h6>
<Link to="/reset">Forgot password ?</Link>
</h6>
</div>
</div>
)
}
export default Signin
and the result is
code: 403
message: "invalid csrf token"
What should I do?
Hi, I think I found something different in route management at restana
. Similar to express, restana
was allowed to continue to the next
route or path, but now something happened because in the last middleware next
is an object and not a function. Example:
service.get('/try', (req, res, next) => { next() }, (req, res, next) => { if (typeof(next) == 'object') res.send('Oops'); else next() })
service.get('/ok', (req, res, next) => { res.send('Ok') })
Congrats
Hi!
In the examples, I did not find examples of get params of the POST request.
Found example in the repository of the project that uses your framework.
request.body
But it is not available from TypeScript.
Error in index.d.ts
? Maybe it's worth adding body?: Record<string, string>
?
https://github.com/jkyberneees/ana/blob/d271aacb07b13c963501ff6620396d38866120ce/index.d.ts#L27-L30
Or am I doing something wrong? :)
Thanks!
upd:
I've checked - there the parameters of the POST request actually passed (casted as (request as unknown as Record<string, string>)
)
how to config cors ?
While trying to use restana with http2/https with typescript I've got some errors.
Here's the code :
import http2 from "http2";
import pem from "pem";
import restana from 'restana'
pem.createCertificate({ days: 1, selfSigned: true }, async (err, keys) => {
try {
if (err) console.error(err);
const service = await restana({
server: http2.createSecureServer({
cert: keys.certificate,
key: keys.clientKey
})
});
service.get("/", (req, res) => {
res.send(req.url);
});
await service.start(8080);
} catch (error) {
console.error(error);
}
});
Here's the error :
Type 'Http2SecureServer' is missing the following properties from type 'Server': maxHeadersCount, timeout, headersTimeout, keepAliveTimeoutts(2739)
index.d.ts(116, 5): The expected type comes from property 'server' which is declared here on type 'Options<Protocol.HTTP>'
Here's the code for the https :
import https from "https";
import pem from "pem";
import restana from "restana";
pem.createCertificate({ days: 1, selfSigned: true }, async (err, keys) => {
try {
if (err) console.error(err);
const service = await restana({
server: https.createServer({
cert: keys.certificate,
key: keys.clientKey
})
});
service.get("/", (req, res) => {
res.send(req.url);
});
await service.start(8080);
} catch (error) {
console.error(error);
}
});
Here's the error :
Argument of type '{ server: Server; }' is not assignable to parameter of type 'Options<Protocol.HTTP>'.
Property 'errorHandler' is missing in type '{ server: Server; }' but required in type 'Options<Protocol.HTTP>'.ts(2345)
index.d.ts(124, 5): 'errorHandler' is declared here.
Here's my tsconfig :
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"baseUrl": "src",
"esModuleInterop": true,
"lib": ["dom", "esnext"],
"module": "commonjs",
"moduleResolution": "node",
"outDir": "dist",
"pretty": true,
"removeComments": true,
"resolveJsonModule": true,
"target": "esnext"
},
"exclude": ["node_modules", "tests/**/*.ts", "dist/**/*.ts"],
"include": ["src/**/*.ts"]
}
Hello folks, just a simple question, will there be support for Open API V3 anytime soon? Thanks.
how to configure restana with socket.io,
I'm working on migrating a service from express. One of the routes currently has 4 middlewares and the TS compiler is giving me an error: Expected 2-5 arguments, but got 6
.
app.post("/api/upload", checkType, processFile, uploadFile, cleanup, handler)
After some digging, I think I found the source of the issue in the type declaration file. It seems odd to me that one could only place up to three middlewares before the handler, and after that would have to switch to a different pattern and use an array for the middlewares, placed after the handler. (Also, side note, the second block seems like a duplicate of the first one?)
interface RegisterRoute<P extends Protocol> {
(
path: string,
handler: RequestHandler<P>,
middlewares?: RequestHandler<P>[]
): Service<P>
// this seems like a duplicate?
(
path: string,
handler: RequestHandler<P>,
middlewares?: RequestHandler<P>[]
): Service<P>
(
path: string,
middleware1: RequestHandler<P>,
handler: RequestHandler<P>,
): Service<P>
(
path: string,
middleware1: RequestHandler<P>,
middleware2: RequestHandler<P>,
handler: RequestHandler<P>,
): Service<P>
(
path: string,
middleware1: RequestHandler<P>,
middleware2: RequestHandler<P>,
middleware3: RequestHandler<P>,
handler: RequestHandler<P>,
): Service<P>
}
Is it not possible to use a rest parameter, since all middlewares and handlers are RequestHandler<P>
?
interface RegisterRoute<P extends Protocol> {
(
path: string,
...middlewaresAndHandler: RequestHandler<P>[]
): Service<P>
}
The link https://thejs.blog/2019/07/12/restana-static-serving-the-frontend-with-node-js-beyond-nginx/ at https://github.com/jkyberneees/ana#serving-static-files does no longer work, it seems the domain name does not resolve.
Maybe replace it with a small inline example?
i am confused, where to start build rest api using this framework, thanks before
i have request url like this
someurl?foo=bar&luck=query
how i get foo & luck query string params ?
i had try req.query.foo but undefined
thanks before
Any possible way to render php?
Is your feature request related to a problem? Please describe.
No, it's not a problem but a suggestion, if is possible and valuable.. but feel free to close if not.
Describe the solution you'd like
Possibility to specify the verb like a string instead specific method. It's useful for example if you want parse o build dynamic routes without other libs (for performance/minimalist solutions).
f.e. possibility to write this:
server.get('/rest', function (req, res) {
res.send('ana')
})
in this way:
server.api('GET', '/rest', function (req, res) {
res.send('ana')
})
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Not necessary, imho.
Bye 👋
ps. ah I forgot... I love this fw, compliments.
Is it possible to return a .html file as response? How to do this?
I see there's a lot of code to test out various frameworks, but I don't see any scripts to run those tests. I've been using https://github.com/fastify/benchmarks to compare what I've done to verify no performance regressions, but it would be nice to run this suite as well.
thank you for this leightweight framework, i had a problem
when i use with restana with http2 when socket.io handshake , it say error during handshake: error 403
but with https its working perfectly.
thank you for your answer before.
Hi, is there any way to expose the router generated from restana?
I'm mainly interested in doing a router.prettyPrint()
as supported by find-my-way, but I couldn't find any property/method of the service that returns the router.
Hello and thanks for fastest Node.js web-framework. I am impressed when see result of combination of turbo-http
+ ana
(restana
).
But i need some of Express method for make good application backend.
Here some of list
app.get()
app.set()
app.disable()
And missing some of instance methods, such as
Request.prototype.on(event, fn)
(called from compression > turbo-http
module)Request.prototype.emit(event, fn)
(called from compression > turbo-http
module)Response.prototype.getHeader()
(called from compression > turbo-http
module)Response.prototype.getAllHeaders()
(called from compression > turbo-http
module)Response.prototype._implicitHeaders
(called from turbo-http
module)Response.prototype._implicitHeader
(called from turbo-http
module)How to make it work or edit instance, thank you again :)
I would like to create a dual http and http2 server and would like to use restana for routing both with a shared service. With node core, I can
const handler = (req, res) => {};
const httpServer = http.createServer(opts, handler);
const http2Server = http2.createSecureServer(opts, handler);
Sharing one restana service for both servers seems impossible because it can take only a single server in the options. I'd suggest either making the router accessible in (req, res) => {}
format so it can be plugged into node servers (similar to express.Router
) or alternatively make restana()
accept multiple servers on creation.
I was wondering if restana
(or find-my-way
, or other) could provide multiple callback functions to handle a request, like route handlers in express. This is the main impact that I have for migrating to restana
. restana
is great, well thought, thanks.
Hi, first of all, thank you very much for this project and for being so kind when replying to the issues here.
With express js, I use router objects outside the main server.js file; from this file I require all the router objects and apply them by using app.use('/prefix', routerObj)
.
My main concern is code organization but I don't know if using router objects is the best way to do it with express.
Anyways, it seems restana does not implement a Router Object like express (does it?).
So, given all this, do you have any suggestions for code organization using restana?
Thank you!
When i am trying to use bodyParser.json() I keep getting an error
2/18/2019 2:23:47 PM error: TypeError: stream.on is not a function
const server = require('restana/libs/turbo-http')
const service = require('restana')({
server: server,
defaultRoute: defaultHandler
})
service.use(bodyParser.urlencoded({
extended: true
}));
service.use(bodyParser.json());
Read Title
ERROR MESSAGE:
{"errClass":"TypeError","code":500,"message":"Cannot read property 'id' of undefined"}
const bp = require('body-parser')
const anumargak = require('anumargak')
const routerFactory = (options) => {
return anumargak(options)}
const service = require('restana')({
server,
routerFactory});
service.get('/user/:id', (req, res) => {
res.send(req.params.id)
})
service.start(3000)
I don't have any idea what's going on . Please help
Hey there! I was experimenting with restana and found it to be indeed much faster than other frameworks, albeit it was at certain points tricky to migrate towards using it in production. I have pointed the project to colleagues and now we are gradually moving some of our projects to restana. We are mostly using Express in production and for us one of the biggest problems was that restana does not support the use of Arrays for paths. While it is trivial to fix it in our routes, due to the amount of routes in our application, this does not seem practical, because of thousands of routes like that across our projects. Therefore, we are using a patched version of restana that implements this feature. I wanted to make a pull request with the change we've made, but then I thought that I might be missing something. Is there any specific reason why this feature is not implemented?
app.get('/one/', function (req, res) {
res.send('something')
})
app.get('/two/', function (req, res) {
res.send('something')
})
function theBestFunction (req,res) {
res.send('something')
}
app.get('/one/', theBestFunction)
app.get('/two/', theBestFunction)
app.get(['/one/', '/two/'], function (req, res) {
res.send('something')
})
It kind of bothers me that the repo is named ana
while the package is called restana
. Maybe rename it to match the package?
Title ^
Did this http.routes();
where http
is require('restana')();
Used to work on v3, not anymore on v4
Is there a way to create modular router without creating 'service' instance and calling 'service.newRouter()' first?
Like with express.Router
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
var birds = require('./birds')
// ...
app.use('/birds', birds)
Hi,
I would like to contribute TypeScript definitions for this package. Would you agree to embed them in the package?
how to configure restana with socket.io, i try to config like
`const server = require('http').createServer(app)
const io = require('socket.io')(server)
io.on('connection', client => {
console.log('[New client connected]', client.id);
console.log('[socket]', client);
client.on("disconnect", () => {
console.log('[Client disconnected]');
})
})`
but doesn't work for listening
as can see from here it returns a Map:
https://github.com/mafintosh/turbo-http/blob/master/lib/request.js#L29
restana try to make it backward compatible by reinstall headers
property:
https://github.com/jkyberneees/ana/blob/master/libs/turbo-http.js#L18
yet simply req.headers = getAllHeaders()
is not enough as direct index will fail:
console.log(req.headers['content-length'])
Hi,
If I understand the code correctly, the property options
in the service interface is overridden by the HTTP method of the same name. If you want to have this reference, you should renamed it to something else.
Hello,
When adding a query string to a POST request it returns 404
code style :
service.use("/path/to/entity", router_entity);
router_entity defines :
router.post("/", async (req, res, next) => {
I tried with and without swagger middleware but got same result.
Any advise ?
Regards,
Hi all.
response.send should support the following variable types:
I faced an issue while working with this awesome micro framework.
Some third-party middlewares relies on req.originalUrl
to work. Example: https://www.npmjs.com/package/session-middleware
I had to add an extra middlware to solve this problem.
service.use((req,res, next) => {
if (!req.originalUrl)
req.originalUrl = req.url
next()
})
It worked for my case, but it would be good to have this property in the req
object as well.
I checked express
and sails
and both have this property in req
object.
Do you think it is possible to have it available?
The data check in response-extensions.js
is too weak. When using res.send()
with a buffer, it converts the response to JSON.
if (typeof data === 'object') { // Buffers should be excluded.
// transparently setting the 'content-type' header if JSON
res.setHeader('content-type', 'application/json')
params.data = JSON.stringify(params.data)
}
Hi!
Im using serve-static to serve static files with restana, but I need to specify the route and trim ".html" part.
For example the url http://localhost:3000/login.html I need to convert into http://localhost:3000/login
How can I do it?
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.