In fastify, is there a way I can add an alias to a route/ path? Basically, having two paths be handled the same way. This is useful for migrating an APIs.
I understand that I can abstract the handler function into a named function, and pass that function to both routes. I am just wondering if there's another way to do so?
No, there is not the feature to set an array of routes to one handler (here the registration logic if you would like to add this feature).
I would suggest registering routes like this:
['/', '/alias'].forEach(path => {
fastify.route({
method: ['GET'], // you could define multiple methods
url: path,
handler: mySharedHandler
})
})
Related
I tried to migrate my express server code from js to typescript and ran into issues when trying to access fields I added to the request object in my own middleware functions.
For example, I am doing something like this:
app.use((req, res, next) => {
let account = checkAuthentication(req);
if(account) {
req.authenticated = true;
req.account = account;
next();
}
});
Now I want to access those properties later on in my other middleware functions, but the .d.ts file from #types/express defines the req object the same way for all middleware functions of course.
Now I came up with two ways to deal with this, but both seem bad:
Use a typeguard in every middleware function. But then I add useless code to the js output because my routes are setup in a way so that I know at "compile" time what shape my req object has in each middleware function.
Use a type assertion in every middleware function. But then I don't get the benefits of typescript, despite writing my code so that all types are know at compile time, because I basically disable typechecking for the req object then.
So my question is: How, if at all, can I utilize typechecking in that scenario? If I can't, does that mean a framework like express is impossible in a statically typed language (like C#)?
You can use module augmentation to extend the Request type defined in the express module
declare global {
namespace Express {
export interface Request {
account: Account;
authenticaticated: boolean
}
}
}
Right now I have two routes, invoking the same method.
Let's say the method's name is myMethod
And two routes are / and /:params
router.get("/", myMethod);
router.get("/:param", myMethod);
Since in both cases I have to invoke the same method, I want to use a single route to invoke the myMethod. Something like this,
router.get('/' or '/:param', methodName);
If it is possible, then how can I do this?
You can use an array :
router.get(['/', '/:param'], myMethod);
I would like to add method such as view and json to the context object passed to my controllers. I do this in a middleware that runs before everything else:
async function(ctx, next){
ctx.view = view.bind(ctx);
ctx.json = json.bind(ctx);
await next()
ctx.renderer.render();
}
these methods set some conventional configuration object (Renderer) that the middleware interprets and then renders out the actual response by setting the correct ctx.body. That allows me to switch template language easily and have an easier time combining API and Template requests.
Except it doesn't work because after await next() the ctx.renderer is the default one, not the one set by controllers. I suspect it's a namespacing issue, but I am not sure where it comes from.
What's the best practice to attach functions to the context that can reference context without it being passed to them?
Ok it's here in the docs I just missed it, the docs are inside a repo and are not hosted, which makes them hard to navigate.
TL;DR: use app.context to access the context prototype. Adding functions there attaches them to the context object and allows you to use this from within to access it.
What is the best way to define custom functions in loopback api that can be used in models defined ?
For example a basic express application can have functions in helper folder on root directory, but doing same in loopback is not recommended and does not maintain loopback way.
Any help would be highly appreciated.
This is very well documented.
Custom logic can be placed in
boot scripts
middlewares
models:
remote methods
remote hooks
operation hooks
application-decoupled logic can very well be put in helper folders, separate folders at root level, etc. There is nothing wrong with modularizing your program this way, it is actually a good thing.
As mentioned by others, the Loopback documentation answers your question like this:
Adding logic to models - adding remote methods, remote hooks and operation hooks.
Defining boot scripts - writing scripts (in the /server/boot directory) that run when the application starts.
Defining middleware - adding custom middleware to the application .
That's a great answer if you have custom functions for a particular model, boot script, or middleware. And as Dharmendra Yadav said, mixins can be another option:
You can use mixins to perform different common actions on models such as observing changes using operation hooks and adding model attributes.
But what about code that simply doesn't fit into any of those categories?
I don't have experience with a lot of web frameworks, but one framework I have used is Grails, which is very opinionated and gives you a place for just about everything. And if your code doesn't fit into any of those categories, they give you a place for that too:
src/main/groovy - Supporting sources
So when I ran into this same problem in Loopback, I just created a src directory under server and that's where I put some helper classes that don't seem to fit anywhere else. And I include them as needed:
const HelperClass = require('../src/HelperClass');
HelperClass.helperFunction()...
Of course you can name the folder however you'd like: src, helpers, support, whatever. And then put it under common or server as appropriate.
The best way to define functions in loopback i found is to use mixins. Here is the sample way of doing so..
https://loopback.io/doc/en/lb3/Defining-mixins.html
You can inherit these defined mixins into your models through .json of your model with {mixins:yourmixin.js}, nice and easy.
Here's some sample code to get you headed in the right direction.
mynewmodel.js
http://domain/api/mynewmodel/myfunc.js
function myfunc(data, callback) {
// ** Put your code here **
console.log('myfunc');
}
function remoteMethod(model) {
model.remoteMethod(
'myfunc',
{
http: { verb: 'post' },
accepts: { arg: 'data', type: 'data' },
returns: [
{ arg: 'returndata', type: 'data' }
]
}
)
}
UPDATE
Generally your js files go in common/models
Is there a way in Loopback 4 to use the #get() decorator (or any another one), passing the path but not generating the open api spec for this route?
By passing a special param / using the #operation or anything?
Thank you.
There is an undocumented spec option 'x-visibility': 'undocumented' for the operation decorators #get, #post, etc. which might fit your needs. Here is an simplified example:
#get('/test', {
responses: {},
'x-visibility': 'undocumented',
})
async test() {
// business logic
}
Here are some references where it is used:
rest.server.open-api-spec.unit.ts#L149
uml.controller.ts#L23