diff --git a/README.md b/README.md index bc87a44e..8f93a58f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Ziggy provides a JavaScript `route()` function that works like Laravel's, making - [**Filtering Routes**](#filtering-routes) - [Including/excluding routes](#includingexcluding-routes) - [Filtering with groups](#filtering-with-groups) +- [**Error Handling**](#error-handling) - [**Other**](#other) - [**Contributing**](#contributing) @@ -496,6 +497,22 @@ To expose multiple groups you can pass an array of group names: > Note: Passing group names to the `@routes` directive will always take precedence over your other `only` or `except` settings. +## Error Handling +For error handling you can be strict which means to stop the execution of your app, or graceful which means to continue executing your app and just show out a red console error and fallback to a specific url like `#`. +``` +// config/ziggy.php + [ + 'graceful' => true, + 'fallback_url' => '#' + ] + ... +] +``` + + ## Other ### TLS/SSL termination and trusted proxies diff --git a/src/Ziggy.php b/src/Ziggy.php index 9b3be04a..d5a55159 100644 --- a/src/Ziggy.php +++ b/src/Ziggy.php @@ -163,6 +163,10 @@ public function toArray(): array 'defaults' => method_exists(app('url'), 'getDefaultParameters') ? app('url')->getDefaultParameters() : [], + 'errors' => [ + 'graceful' => config('ziggy.errors.graceful',false), + 'fallback_url' => config('ziggy.errors.fallback_url','#'), + ], 'routes' => $this->applyFilters($this->group)->toArray(), ]; } diff --git a/src/js/Router.js b/src/js/Router.js index e05ac285..1ecc4f15 100644 --- a/src/js/Router.js +++ b/src/js/Router.js @@ -19,11 +19,18 @@ export default class Router extends String { if (name) { if (!this._config.routes[name]) { - throw new Error(`Ziggy error: route '${name}' is not in the route list.`); - } + // Throw the error only if not gracefull + if(!this._config.errors.graceful) + throw new Error(`Ziggy error: route '${name}' is not in the route list.`); - this._route = new Route(name, this._config.routes[name], this._config); - this._params = this._parse(params); + // Otherwise set the route and params to null and show console error + this._route = this._params = null; + console.error(`Ziggy error: route '${name}' is not in the route list.`) + } + else{ + this._route = new Route(name, this._config.routes[name], this._config); + this._params = this._parse(params); + } } } @@ -37,6 +44,11 @@ export default class Router extends String { * @return {String} */ toString() { + + // If the route is null return the fallback_url + if(!this._route) + return this._config.errors.fallback_url + // Get parameters that don't correspond to any route segments to append them to the query const unhandled = Object.keys(this._params) .filter((key) => !this._route.parameterSegments.some(({ name }) => name === key)) diff --git a/tests/Unit/RouteModelBindingTest.php b/tests/Unit/RouteModelBindingTest.php index 9ad92e17..4fa6d1d4 100644 --- a/tests/Unit/RouteModelBindingTest.php +++ b/tests/Unit/RouteModelBindingTest.php @@ -234,7 +234,7 @@ public function can_merge_implicit_and_scoped_bindings() /** @test */ public function can_include_bindings_in_json() { - $json = '{"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"users":{"uri":"users\/{user}","methods":["GET","HEAD"],"parameters":["user"],"bindings":{"user":"uuid"}},"admins":{"uri":"admins\/{admin}","methods":["GET","HEAD"],"parameters":["admin"],"bindings":{"admin":"uuid"}},"tags":{"uri":"tags\/{tag}","methods":["GET","HEAD"],"parameters":["tag"],"bindings":{"tag":"id"}},"tokens":{"uri":"tokens\/{token}","methods":["GET","HEAD"],"parameters":["token"]},"users.numbers":{"uri":"users\/{user}\/{number}","methods":["GET","HEAD"],"parameters":["user","number"],"bindings":{"user":"uuid"}},"users.store":{"uri":"users","methods":["POST"]},"comments":{"uri":"comments\/{comment}","methods":["GET","HEAD"],"parameters":["comment"],"bindings":{"comment":"uuid"}},"replies":{"uri":"replies\/{reply}","methods":["GET","HEAD"],"parameters":["reply"],"bindings":{"reply":"uuid"}},"posts":{"uri":"blog\/{category}\/{post}","methods":["GET","HEAD"],"parameters":["category","post"],"bindings":{"category":"id","post":"slug"}},"posts.tags":{"uri":"blog\/{category}\/{post}\/{tag}","methods":["GET","HEAD"],"parameters":["category","post","tag"],"bindings":{"category":"id","post":"slug","tag":"slug"}}}}'; + $json = '{"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"users":{"uri":"users\/{user}","methods":["GET","HEAD"],"parameters":["user"],"bindings":{"user":"uuid"}},"admins":{"uri":"admins\/{admin}","methods":["GET","HEAD"],"parameters":["admin"],"bindings":{"admin":"uuid"}},"tags":{"uri":"tags\/{tag}","methods":["GET","HEAD"],"parameters":["tag"],"bindings":{"tag":"id"}},"tokens":{"uri":"tokens\/{token}","methods":["GET","HEAD"],"parameters":["token"]},"users.numbers":{"uri":"users\/{user}\/{number}","methods":["GET","HEAD"],"parameters":["user","number"],"bindings":{"user":"uuid"}},"users.store":{"uri":"users","methods":["POST"]},"comments":{"uri":"comments\/{comment}","methods":["GET","HEAD"],"parameters":["comment"],"bindings":{"comment":"uuid"}},"replies":{"uri":"replies\/{reply}","methods":["GET","HEAD"],"parameters":["reply"],"bindings":{"reply":"uuid"}},"posts":{"uri":"blog\/{category}\/{post}","methods":["GET","HEAD"],"parameters":["category","post"],"bindings":{"category":"id","post":"slug"}},"posts.tags":{"uri":"blog\/{category}\/{post}\/{tag}","methods":["GET","HEAD"],"parameters":["category","post","tag"],"bindings":{"category":"id","post":"slug","tag":"slug"}}}}'; $this->assertSame($json, (new Ziggy)->toJson()); } diff --git a/tests/Unit/ZiggyTest.php b/tests/Unit/ZiggyTest.php index 597ff4c9..9e91d4e7 100644 --- a/tests/Unit/ZiggyTest.php +++ b/tests/Unit/ZiggyTest.php @@ -566,6 +566,10 @@ public function route_payload_can_array_itself() 'url' => 'http://ziggy.dev', 'port' => null, 'defaults' => [], + 'errors' => [ + 'graceful' => false, + 'fallback_url' => '#', + ], 'routes' => [ 'home' => [ 'uri' => 'home', @@ -616,6 +620,10 @@ public function route_payload_can_json_itself() 'url' => 'http://ziggy.dev', 'port' => null, 'defaults' => [], + 'errors' => [ + 'graceful' => false, + 'fallback_url' => '#', + ], 'routes' => [ 'postComments.index' => [ 'uri' => 'posts/{post}/comments', @@ -633,7 +641,7 @@ public function route_payload_can_json_itself() ], ]; - $json = '{"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]},"postComments.show":{"uri":"posts\/{post}\/comments\/{comment}","methods":["GET","HEAD"],"parameters":["post","comment"],"bindings":{"comment":"uuid"}}}}'; + $json = '{"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]},"postComments.show":{"uri":"posts\/{post}\/comments\/{comment}","methods":["GET","HEAD"],"parameters":["post","comment"],"bindings":{"comment":"uuid"}}}}'; $this->assertSame($expected, json_decode(json_encode(new Ziggy), true)); $this->assertSame($json, json_encode(new Ziggy)); diff --git a/tests/fixtures/admin.js b/tests/fixtures/admin.js index b78a8475..b31ad80f 100644 --- a/tests/fixtures/admin.js +++ b/tests/fixtures/admin.js @@ -1,4 +1,4 @@ -const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"admin.dashboard":{"uri":"admin","methods":["GET","HEAD"]}}}; +const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"admin.dashboard":{"uri":"admin","methods":["GET","HEAD"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { Object.assign(Ziggy.routes, window.Ziggy.routes); } diff --git a/tests/fixtures/custom-pathname.js b/tests/fixtures/custom-pathname.js index 04c74a6c..ddf31ea8 100644 --- a/tests/fixtures/custom-pathname.js +++ b/tests/fixtures/custom-pathname.js @@ -1,4 +1,4 @@ -const Ziggy = {"url":"http:\/\/ziggy.dev\/foo\/bar","port":null,"defaults":{"locale":"en"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; +const Ziggy = {"url":"http:\/\/ziggy.dev\/foo\/bar","port":null,"defaults":{"locale":"en"},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { Object.assign(Ziggy.routes, window.Ziggy.routes); } diff --git a/tests/fixtures/custom-url.js b/tests/fixtures/custom-url.js index 081dfc49..49db9776 100644 --- a/tests/fixtures/custom-url.js +++ b/tests/fixtures/custom-url.js @@ -1,4 +1,4 @@ -const Ziggy = {"url":"http:\/\/example.org","port":null,"defaults":{"locale":"en"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; +const Ziggy = {"url":"http:\/\/example.org","port":null,"defaults":{"locale":"en"},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { Object.assign(Ziggy.routes, window.Ziggy.routes); } diff --git a/tests/fixtures/ziggy-custom.js b/tests/fixtures/ziggy-custom.js index 80443fed..08d7218e 100644 --- a/tests/fixtures/ziggy-custom.js +++ b/tests/fixtures/ziggy-custom.js @@ -1,3 +1,3 @@ // This is a custom template -const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; +const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; export { Ziggy }; diff --git a/tests/fixtures/ziggy.js b/tests/fixtures/ziggy.js index 3d12dedd..ae24079f 100644 --- a/tests/fixtures/ziggy.js +++ b/tests/fixtures/ziggy.js @@ -1,4 +1,4 @@ -const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]},"slashes":{"uri":"slashes\/{slug}","methods":["GET","HEAD"],"wheres":{"slug":".*"},"parameters":["slug"]}}}; +const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"errors":{"graceful":false,"fallback_url":"#"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]},"slashes":{"uri":"slashes\/{slug}","methods":["GET","HEAD"],"wheres":{"slug":".*"},"parameters":["slug"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { Object.assign(Ziggy.routes, window.Ziggy.routes); } diff --git a/tests/js/route.test.js b/tests/js/route.test.js index 85b2120a..5c4684d3 100644 --- a/tests/js/route.test.js +++ b/tests/js/route.test.js @@ -15,6 +15,10 @@ const defaultZiggy = { url: 'https://ziggy.dev', port: null, defaults: { locale: 'en' }, + errors: { + graceful: false, + fallback_url: "#" + }, routes: { home: { uri: '/', @@ -542,6 +546,10 @@ describe('route()', () => { url: 'http://notYourAverage.dev', port: null, defaults: { locale: 'en' }, + errors: { + graceful: false, + fallback_url: "#" + }, routes: { 'tightenDev.packages.index': { uri: 'tightenDev/{dev}/packages', @@ -820,6 +828,10 @@ describe('current()', () => { const config = { url: 'https://ziggy.dev', port: null, + errors: { + graceful: false, + fallback_url: "#" + }, routes: { 'events.index': { uri: 'events', @@ -954,6 +966,10 @@ describe('current()', () => { const config = { url: 'https://ziggy.dev', port: null, + errors: { + graceful: false, + fallback_url: "#" + }, routes: { 'workspaces.processes.index': { uri: '{workspace}/processes', @@ -1370,6 +1386,10 @@ describe('current()', () => { const config = { url: 'https://ziggy.dev', port: null, + errors: { + graceful: false, + fallback_url: "#" + }, routes: { 'events.venues.show': { uri: 'events/{event}/venues/{venue}',