Next.js middleware matcher negate path - javascript

I have a middleware on a Next.js project, and I want to negate my /api/* route.
In other words, I want middleware to run for every route except anything that starts with /api/. I couldn't find an example in the docs.
How do I achieve that (of course, without writing all included routes one by one)?

Looks like the middleware docs have been updated to account for something like this.
nextjs middleware docs
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - static (static files)
* - favicon.ico (favicon file)
*/
'/((?!api|static|favicon.ico).*)',
],
}

You cannot do this with matcher, because it only accepts simple path patterns, therefore you'll need to use conditional statement:
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/')) {
return NextResponse.next()
}
// your middleware logic
}

Related

Use middleware only for json server specific routes

How can I use a middleware ONLY FOR my json-server specific routes? In the json-server docs, I can see the following instructions:
const jsonServerRouter = jsonServer.router('mock-server/db.json')
server.use(customMiddleware)
server.use(jsonServerRouter) // customMiddleware should be executed ONLY FOR this jsonServerRouter
/*
Problem is here, customMiddleware has already been executed,
so following routes will use the middleware too
*/
server.use(otherRoutes)
What I've tried:
// This syntax is similar to the previous code. So it doesnt work
server.use(customMiddleware, jsonServerRouter)
// Passing the middleware to the 'router' function doesnt work
const jsonServerRouter = jsonServer.router('mock-server/db.json', customMiddleware)

How to run one angular app with two urls?

Wanted to know is there any way that we can run one angular 6 app on with two rendering URL ?
Example :
www.domain.com/abc1
www.domain.com/abc2
We have two urls that will be using the same application but the difference is whenever abc1 is rendered data shown is different then the abc2.
Both are sharing the same code/application.
Not sure how to do this or that's possible ?
If the data comes from backend and the Angular apps differ in datasource you should try this:
ng build --prod --base-href "/abc1/"
ng build --prod --base-href "/abc2/"
you can create different layouts based on the view you want to load.
An alternative approach to the others listed would be to actually use the same app for this, just on different routes.
Say you are listing Todos, but on /abc1 they com from server-1.com/api, and on /abc2, they come from server-2.com/api.
You'd first create your app routing module, to capture the "subdomain" (as you called it, although it's actually a virtual directory) part of the url. So, app-routing.module.ts has this for routes:
const routes = [
{ path: ':subdomain', component: TodosComponent },
];
// and the rest of it.
(For simplicity I'm not doing modules here).
So now your TodosComponent simply reads the "subdomain" and fetches stuff from proper backend:
class TodosComponent implements OnInit {
// inject the backend service (or more) and activated route
constructor(private backend: BackendService,
private route: ActivatedRoute) {
}
// on init, get that route param
ngOnInit() {
this.route.params.subscribe(params => {
// catch the "subdomain" param
const subdomain = params.subdomain;
// now you'd move this to a service, but here:
if (subdomain === 'abc1') {
this.backend.get('http://server-1.com/api').subscribe(...);
} else if (subdomain === 'abc2') {
this.backend.get('http://server-2.com/api').subscribe(...);
} else {
// add more as needed here.
}
})
}
}
Now, this would be the same app that would work completely as a SPA as you switch between subdomains.
In the actual app, your app-routing would pass this down to a (lazy) module, this module would have all the components, services etc built so that you can parametrize all the setup with this url segment/route parameter.

Route ajax calls to path other than one mentioned while making the call

My project is build in C# MVC. Assume its hosted on abc.com.
Ajax call made for a resource for ex on Controller:Home and Method:ClientInfo will be something as :
url: '/Home/ClientInfo'
For Testing purpose I have deployed same project on assume xyz.com/web
In this case my Home page is xyz.com/web.
Now ajax calls made for the resource Controller:Home and Method:ClientInfo with the same ajax url '/Home/ClientInfo' is returning 404 Not Found.
Since the url should be something as
url: '/web/Home/ClientInfo'
One way of handling this is I edit all ajax urls throughout the project which doesn't seems right way.
I have common Layout can I write code there in javascript to route all urls under directory '/web' or is there any other way ?
*Note : I don't have control on web.config of xyz.com to handle the calls and write rules in there.
Please Suggest
You could make a JavaScript file that exports the API routes and import it when you need the routes, so you have one point to change when needed.
example ES6
File called routes.js with API routes:
export const API = '/web/';
export const CLIENT_INFO_API = `${API}home/clientinfo`;
Then whenever you need to use the routes in other files:
//Import routes file
import * as ROUTES from 'routes.js';
//Use the routes
ROUTES.API
ROUTES.CLIENT_INFO_API
example ES5
File called routes.js with API routes:
var routes = {};
routes.API = '/web/';
routes.CLIENT_INFO_API = routes.API+'home/clientinfo';
module.exports = routes;
Then whenever you need to use the routes in other files:
//Import routes file
const ROUTES = require('routes.js');
//Use the routes
ROUTES.API
ROUTES.CLIENT_INFO_API

How to require multiple controllers with express?

So I try to make a full stack project. It has controllers like signup, login, profile etc.
What I do is I require each controller manually, then use them according to the request. For example, I will have
app.use('/signup',signup);
app.use('/login',login);
app.use('/profile',profile);
However, when I build up the complexity of the project,more controllers will be needed, but manually typing everything is not the best practice.
I want to have a more general form, just one line does all the work:
app.use('whatever the link i got',load the corresponding controller);
Maybe the solution will be in different form. How can I achieve this? I need some suggestions.
The simplest solution would probably be to put them all in a controllers directory and then just do this:
const controllers = readdirSync(path.join(__dirname, 'controllers'))
controllers.forEach(controller => {
app.use(`/${controller}`, require(`./controllers/${controller}`))
})
This works great, as long as your routes and controllers are named the same thing. If you need to deal with converting kebab to camel case, there's always lodash.
Assuming you're using express 4, you could take this one step further, and put an index.js in the controllers directory. Inside:
const express = require('express')
const router = express.Router()
const controllers = readdirSync(__dirname))
.filter(f => f !== 'index.js'))
controllers.forEach(controller => {
router.use(`/${controller}`, require(`./${controller}`))
})
module.exports = router
Then you can just use the router like this:
app.use('/', require('./controllers'))

How do I import 400+ modules, and iterate over them in my angular-cli project?

I am about to have 400+ models for use with js-data in my angular2 (angular-cli) app.
my project's structure is this:
- src/
- app/
- services/
- pipes/
- ui/
- data/
- store.ts
- models/
- model1.ts
- model2.ts
- ...
- model400.ts
In the store, I need to import, and add the mapping to the store.
The model files are actually just mapper configs for js-data 3.
currently, they look something like this:
// src/app/data/models/model1.ts
export default {
schema: {
name: 'model1',
properties: {
id: { type: 'integer' }
}
},
relations: {}
}
and my store currently looks like this:
// src/app/data/store.ts
import {
DataStore,
Mapper,
Record,
Schema,
utils
} from 'js-data'
import {HttpAdapter} from 'js-data-http'
declare var require: any
export const adapter = new HttpAdapter({
// Our API sits behind the /api path
basePath: '/api'
});
export const store = new DataStore({});
store.registerAdapter('http', adapter, { default: true });
import { model1Config} from './models/model1';
import { model2Config } from './models/model2';
import { model3Config } from './models/model3';
// at this point, I give up, cause this is more tedious
// than cutting grass with a finger nail clipper
store.defineMapper('model1', model1Config);
store.defineMapper('model2', model2Config);
store.defineMapper('model3', model3Config);
If there is anyway to iterate over every file in the models folder, that would be great.
angular-cli is supposed to eventually compile all the ts/js to a single js file, so I don't need to worry about anything that couldn't run on the client side.
(so, I have broccoli, and whatever other build tools are bundled with that, I just don't know if any of them would be useful to me for this situation)
You could use an index file, which you can use for your imports. for example in your models folder an index file which just exports every model for you like this:
// ...../models/index.ts
export * from './models/model1';
export * from './models/model2';
then in your other files you can import them like this:
import {model1Config, model2Config, model3Config } from "path/to/models/index";
...
You have to define the exports somewhere. Using a file which functions as a "export collection" saves you at least a lot lines of code (and a lot of time if you're using a good IDE).
Setting up the the index with your x-hundreds of models still is tedious. Maybe a little script with gulp could help.

Categories