I'm using swagger with node and I have a need to dynamically set the path to controllers at node start. For instance, the path will either be /api/controllers/foo/ or /api/controllers/bar/.
The swagger-node documentation describes the swagger configuration object. I can define the directories to search in for controllers or the router to use to resolve controllers, but overriding the existing/default swagger-tools router seems like overkill, and setting the controllers directories doesn't work because I need the directory to be either foo or bar, not both.
# swagger configuration file
# values in the swagger hash are system configuration for swagger-node
swagger:
fittingsDirs: [ api/fittings, node_modules ]
defaultPipe: null
swaggerControllerPipe: swagger_controllers # defines the standard processing pipe for controllers
# values defined in the bagpipes key are the bagpipes pipes and fittings definitions
# (see https://github.com/apigee-127/bagpipes)
bagpipes:
_router:
name: swagger_router
mockMode: false
mockControllersDirs: [ api/mocks ]
controllersDirs: [ api/controllers ]
_swagger_validate:
name: swagger_validator
validateResponse: true
# pipe for all swagger-node controllers
swagger_controllers:
- onError: json_error_handler
- cors
- swagger_security
- _swagger_validate
- express_compatibility
- _router
# pipe to serve swagger (endpoint is in swagger.yaml)
swagger_raw:
name: swagger_raw
# any other values in this file are just loaded into the config for application access...
I haven't been able to find any clear concise way to do this. Seems like I'm missing something. Does anyone have experience dynamically setting the controller directory dynamically? What's the best approach here?
Related
I've created an app with fastify generate but nested routes are giving me 404. index.ts works a directory but anything else I add is not found. I have /a/b/index.ts which works but /a/b/c.ts which doesn't. But if i move c.ts to the parent dir, it's detected. And i have fastify.get('/c'... on c.ts. How can I fix this?
Fastify is about security, so you need to check the plugins' documentation you are using under the hood.
In your case, you must change the app.ts file like so:
void fastify.register(AutoLoad, {
dir: join(__dirname, 'routes'),
maxDepth: 4, // default is 2
options: opts
})
by doing this, fastify-autoload will search for nested folders deep to 4 levels.
Then you will be able to call: http://127.0.0.1:3000/a/b/c/c assuming you created src/routes/a/b/c/c.ts
I have installed Loopback 4, and mounted my legacy Loopback 3 app into it as part of my migration - all good so far.
However my (swagger-ui shaped) explorer renders expanded by default - and there are a LOT of endpoints and services - making it very hard to find what I'm looking for.
My instinct tells me I should be able to add a configuration here in my application.ts - but I cannot find anything.
this.configure(RestExplorerBindings.COMPONENT).to({
path: '/explorer',
docExpansion:'none' <<<<< this is what I would expect/like
});
this.component(RestExplorerComponent);
Has anyone been able to accomplish this? It seems from the forums there are a lot of requests for something like this.
You could try this.
https://www.npmjs.com/package/#loopback/rest-explorer
Overriding the Swagger UI index.html
For more flexibility, the indexTemplatePath property can be used to allow full customization of Swagger UI configuration options.
indexTemplatePath should be an absolute path to a html.ejs template.
To get started, download the default index.html.ejs,
add /explorer/index.html.ejs to your project, and update the configuration:
this.configure(RestExplorerBindings.COMPONENT).to({
// For example, create a directory "explorer" at the same level
// as "src" and "node_modules" in your applciation structure
indexTemplatePath: path.resolve(__dirname, '../explorer/index.html.ejs'),
});
you can then add
docExpansion: 'none',
inside the index.html.ejs file.
const ui = SwaggerUIBundle({
url: '<%- openApiSpecUrl %>',
dom_id: '#swagger-ui',
deepLinking: true,
filter: true,
docExpansion: 'none',
defaultModelsExpandDepth: 0,
defaultModelExpandDepth: 0,
presets: [
SwaggerUIBundle.presets.apis,
// SwaggerUIStandalonePreset
SwaggerUIStandalonePreset.slice(1) // Disable the top bar
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: 'StandaloneLayout'
})
I have my code
app.set('views', path..);
originally placed in server.js and I tried to segregate/factor it into a config.server.js (see link), there I implemented underscoreJS each to loop through the modules by their folders' names in my modules/ directory. ['core', 'xt_syncs']. Problem with this trick I try playing is that, app.set('views',..) can't be a Singleton (which loads many things at once). The app.set('views',..) can only have 1 URI for 'views' (module specific, my app contains several modules: core, xt_syncs as you see in the structure), and the app.set appear to fail, and be overwritten by the static uri to modules/second_module.
I write the app myself, picking the middlewares/components I want. I'm trying to reuse some of the assets from MEANjs, mean-stack-relational (MVC, I prefer modules architecture to MVC, that's why my attempt is to build mine), and SEANjs (quite too complex, the stack requires Redis and MySQL5.7, I try building mine so I can get a good understanding of things flow on the fly and exclude Redis and MySQL upgrade).
Now back to the question, obviously, you see in MEANjs and SEANjs , they do in their default.js file:
views: ['modules/*/client/views/**/*.html'],
routes: ['modules/!(core)/server/routes/**/*.js', 'modules/core/server/routes/**/*.js']
QUESTIONS:
1/ How can I implement similar pattern in my app? Notice in the MEANjs and SEANjs, there is * as in modules/*/client and ! as in modules/!(core)/server. app design advices and coding help, please. (this part of the question is not yet addressed)
2/ How related the default.js is to the config.js (initGlobalConfigFolders,initGlobalConfigFiles,...)? I try to wrap my head around to understand config.js and find clues of the glueing. Maybe, my modules[module] as in
modules[module] = {
client: {},
server: {}
};
is one step closer to what they built in the initGlobalConfigFolders method.
3/ Is using build tool (Grunt, Gulp, or Webpack) a must here to achieve that? If so, Can you show me how? (build tool incorporation is in my planning). How can you
Thank you very much.
This patch hinted at implementing app.set('views', view_paths); // where view_paths can be an array of views folders.
2 & 3. Awaiting help and answers.
I'm building an isomorphic React/React-Router/Redux/Webpack application and I'm attempting to implement server side rendering.
My directory looks like:
/client
/actions
/components
/containers
/server
/server.js
In my webpack config, I have aliases set up for all the folders inside client:
var path_base = path.resolve(__dirname, '..');
const resolve = path.resolve;
const base = function() {
var args = [path_base];
args.push.apply(args, arguments);
return resolve.apply(resolve,args);
};
const resolve_alias = base.bind(null, 'src/client');
const aliases = [
'actions',
'components',
'constants',
'containers',
'middleware',
'reducers',
'routes',
'store',
'styles',
'utils',
'validation'
];
so that inside the code that gets bundled by webpack, I can do:
import { Widget } from 'components';
and that import gets resolved by webpack.
Now in my server code, in order to do the rendering, I have to import some of my client files, like routes/index.js. The problem I'm running into when I import my routes file, it's using a webpack alias to another file, say components or containers so naturally, the node js require system can't resolve it.
How do I fix something like that? I looked at this question and it talks about essentially setting up the same aliases that exist in webpack with mock-require. But then the issue becomes that my routes file imports all my components which then all import things like stylesheets, images, etc. Should I then be using something like webpack-isomorphic-tools?
The guides I've been looking at (this for example) are all great at showing how server side rendering is accomplished but none of them really talk about how to resolve all the requires and whatnot.
After battling with this issue for 2 days I settled on babel-plugin-webpack-alias.
What you need to do to resolve paths with that is:
$ npm install --save-dev babel-plugin-webpack-alias
Add the plugin to your .babelrc
Add the aliases to your webpack.config (make sure you use path.join())
Refer to this post if you have problems loading styles
The other option I tried was universal-webpack but I found it to be a bit verbose. If you want to see roughly how the whole server-side loading works, you can check out this video.
If you really want them, run your server side code through babel and use this plugin: https://www.npmjs.com/package/babel-plugin-module-alias which will let you do the same thing as webpack.
Edit: This one works a lot better: https://github.com/jagrem/babel-resolve-relative-module it allows multiple paths
Try to use NODE_PATH. Node will always look for a module in this path during require calls. It allows to short cut your relative paths as you want.
// turn this
import {Widget} from '../../components';
// into this
import {Widget} from 'components';
See Node.js docs for more information.
P.S. this thing is very sensitive, so use it carefully. Now your code tightly depends from the environment and may break somewhere.
If you use webpack-isomorphic-tools then it'll take your webpack config into account for your server side which will make all your aliases work.
https://www.npmjs.com/package/webpack-isomorphic-tools
I'm designing an app with node.js and Express, and I was wondering if it was possible to move certain routing logic out of the app.js file. For exapmle, my app.js currently contains:
app.get('/groups',routes.groups);
app.get('/',routes.index);
Is there a way to move this logic out of the app.js file, and only have something like:
app.get('/:url',routes.get);
app.post('/:url",routes.post);
such that all GET requests would be processed by routes.get and all POST requests processed with routes.post?
You could pass a regular expression as the route definition:
app.get(/.+/, someFunction);
This would match anything. However, if you simply want to move your route definitions outside of your main app.js file, it is much clearer to do something like this:
app.js
var app = require('express').createServer();
...
require('routes').addRoutes(app);
routes.js
exports.addRoutes = function(app) {
app.get('/groups', function(req, res) {
...
});
};
This way, you're still using Express' built-in routing, rather than re-rolling your own (as you'd have to do in your example).
FULL DISCLOSURE: I am the developer of the node module mentioned below.
There is a node module that does kind of what you're asking for (and will, eventually, do more). It offers automatic routing based on convention over configuration for express. The module name is honey-express, but is currently in alpha development and not yet available on NPM (but you can get it from the source at https://github.com/jaylach/honey-express.
A short example of how it works: (Please note that this coffeescript)
# Inside your testController.coffee file. Should live inside /app/controllers
honey = require 'honey-express'
TestController = new honey.Controller
index: ->
# #view() is a helper method to automatically render the view for the action you're executing.
# As long as a view (with an extension that matches your setup view engine) lives at /app/views/controller/actionName (without method, so index and not getIndex), it will be rendered.
#view()
postTest: (data) ->
# Do something with data
Now, inside your app.js file you just have to setup some simple configuration:
# in your app.configure callback...
honey.config 'app root', __dirname + '/app'
app.use honey.router()
Now anytime a request comes in, honey will automatically look for a controller with the specified route, and then look for a matching action.. for example -
/test will automatically route to the index/getIndex() method of
testController
/ will automatically route to the index/getIndex() method of the homeController (the default controller is home), if it exists
/test/test will automatically route to the postTest() method of testController if the http method is POST.
As I mentioned, the module is currently in it's alpha state but the automatic routing works wonderfully and has been tested on two different projects now :) But since it's in alpha development, the documentation is missing. Should you decide to go this route, you can look at the sample I have up on the github, look through the code, or reach out to me and I'd be happy to help :)
EDIT: I should also note that honey-express does require the latest (BETA) version of express as it uses features that are not present in 2.x of express.