A lightweight library with many features to easy build URLs
[!WARNING]
Breaking changes from 2.x to 3.x
-
UrlBuilder#addParam()
has been removed. UseUrlBuilder#getPathParams().add()
instead -
UrlBuilder#addParams()
has been removed. UseUrlBuilder#getPathParams().addAll()
instead -
UrlBuilder#addOrReplaceParam()
has been removed. UseUrlBuilder#getPathParams().set()
instead -
UrlBuilder#addOrReplaceParams()
has been removed. UseUrlBuilder#getPathParams().setAll()
instead -
UrlBuilder#findParams()
has been removed. UseUrlBuilder#getPathParams().find()
instead -
UrlBuilder#addQueryParams()
has been removed. UseUrlBuilder#getQueryParams().addAll()
instead -
UrlBuilder#addOrReplaceQueryParam()
has been removed. UseUrlBuilder#getQueryParams().set()
instead -
UrlBuilder#addOrReplaceQueryParams()
has been removed. UseUrlBuilder#getQueryParams().setAll()
instead -
UrlBuilder#findQueryParams()
has been removed. UseUrlBuilder#getQueryParams().find()
instead -
UrlBuilder#getQueryString()
has been removed. UseUrlBuilder#getQueryParams().toString()
instead
This library allows :
- Create URLs most easly
- Parse and decompose your URLs
- Ride up in the URL tree
- Make comparisons between URLs
To import the library you just need to run this command :
npm install @innova2/url-builder
const url = UrlBuilder.createFromUrl('http://localhost:8080/users');
// or
const url = UrlBuilder.createFromUrl('/users', 'http://localhost:8080');
// or create new url with the constructor
Add new path segment(s) and params
[!NOTE] All methods (except getBaseUrl) on PathParams object (by
getPathParams()
), return the current PathParams object and not the current UrlBuilder object [!NOTE] Theadd()
andaddAll()
methods on PathParams object does not add the entry if the key already exists. Useset()
orsetAll()
instead
const userId = '170b16cd-ad47-4c9c-86cf-7c83bd40d775';
url.addPath(':id/comments').getPathParams().add('id', userId);
// Or
url.addPath(':id/comments', { id: userId });
Add multiples parameters after adding path segment(s)
const userId = '170b16cd-ad47-4c9c-86cf-7c83bd40d775';
const commentId = '218dd1c4-0bb0-425a-be0b-85427304e100';
url.addPath(':userId/comments/:commentId').getPathParams().addAll({ userId, commentId });
// Or
url.addPath(':userId/comments/:commentId', { userId, commentId });
If you want to add or replace existing param(s), use instead :
const userId = '170b16cd-ad47-4c9c-86cf-7c83bd40d775';
const commentId = '218dd1c4-0bb0-425a-be0b-85427304e100';
url.addPath(':userId/comments/:commentId', { userId: 3, commentId: 1 });
// Without replacement :
url.getPathParams().add('userId', userId);
// Param 'userId' is always : 3
// With replacement :
url.getPathParams().set('userId', userId);
// Param 'userId' is now : 170b16cd-ad47-4c9c-86cf-7c83bd40d775
// Or with multiples parameters
// Without replacement :
url.getPathParams().addAll({ userId: 10, commentId: 5 });
// Param 'userId' is always : 170b16cd-ad47-4c9c-86cf-7c83bd40d775
// Param 'commentId' is always : 1
// With replacement :
url.getPathParams().setAll({ userId: 10, commentId: 5 });
// Param 'userId' is now : 10
// Param 'commentId' is now : 5
Retrieve params
const url = new UrlBuilder()
.getPathParams().addAll({
startDate: '1679737680454',
endDate: '1679937680454',
});
const params = url.getPathParams();
// params contains all path params as Map
const filteredParams = url.getPathParams().filter(([key, value]) => new Date(Number(value)).getDate() === 25);
// filteredParams contains a new Map only with param 'startDate'
Get the first path segment
const rowNum = 10;
const url = UrlBuilder.createFromUrl('http://localhost:8080/rows/:rowNum/cells').addParam('rowNum', rowNum);
url.getFirstPath(); // Output: 'rows'
Get the last path segment
url.getLastPath(); // Output: 'cells'
Delete some path params
const url = new UrlBuilder()
.getPathParams().addAll({
startDate: '1679737680454',
endDate: '1679937680454',
});
url.getPathParams().deleteBy(([key, value]) => new Date(Number(value)).getDate() === 25);
// PathParams no longer contains param 'endDate'
[!NOTE] All methods (except getBaseUrl) on QueryParams object (by
getQueryParams()
), return the current QueryParams object and not the current UrlBuilder object
[!NOTE] The
add()
andaddAll()
methods on QueryParams object does not add the entry if the key already exists. Useset()
orsetAll()
instead Add new query param
const page = 2;
url.getQueryParams().add('page', page);
// or
url.addQueryParam('page', page);
Add multiples query params
const page = 2;
const order = 'DESC';
url.getQueryParams().addAll({ page, order });
If you want to add or replace existing query, use instead :
const page = 2;
const order = 'DESC';
url.getQueryParams().addAll({ page, order });
// Without replacement :
url.getQueryParams().add('page', 3);
// QueryParam 'page' is always : 2
// With replacement :
url.getQueryParams().set('page', 3);
// QueryParam 'page' is now : 3
// Or with multiples parameters
// Without replacement :
url.getQueryParams().addAll({ page: 4, order: 'ASC' });
// QueryParam 'page' is always : 3
// QueryParam 'order' is always : DESC
// With replacement :
url.getQueryParams().setAll({ page: 4, order: 'ASC' });
// QueryParam 'page' is now : 4
// QueryParam 'order' is now : ASC
Retrieve query params
const url = new UrlBuilder()
.getQueryParams().addAll({
style: 'dark',
utm_source: 'Google',
utm_medium: 'newsletter',
utm_campaign: 'summer',
isMobile: 1
});
const queryParams = url.getQueryParams();
// queryParams contains all query params as Map
const filteredQueryParams = url.getQueryParams().filter(([key]) => key.startsWith('utm'));
// filteredQueryParams contains a new Map only with query params 'utm_source', 'utm_medium' and 'utm_campaign'
Delete some query params
const url = new UrlBuilder()
.getQueryParams().addAll({
style: 'dark',
utm_source: 'Google',
utm_medium: 'newsletter',
utm_campaign: 'summer',
isMobile: 1
});
url.getQueryParams().deleteBy(([key]) => key.startsWith('utm'));
// QueryParams no longer contains query params 'utm_source', 'utm_medium' and 'utm_campaign'
Parse file in url
// Consider file part of path segments
const url = UrlBuilder.createFromUrl('http://localhost/users/10.html');
url.getRelativePath();
// Output : /users/10.html
url.getPathSegments();
// Output : ['users', '10.html'];
url.getFile();
// Output : undefined
// Consider file dissociated of path segments
const url2 = UrlBuilder.createFromUrl('http://localhost/users/10.html', true);
url2.getRelativePath();
// Output : /users/10.html
url2.getPathSegments();
// Output : ['users'];
url2.getFile();
// Output : { name: '10', ext: 'html' }
Define file
url.setFile({ name: 'mycover', ext: 'webp' });
url.getFile();
// Output : { name: 'mycover', ext: 'webp' }
Define file from filename
url.setFilename('mycover.webp');
url.getFile();
// Output : { name: 'mycover', ext: 'webp' }
Parse fragment with url
const url = UrlBuilder.createFromUrl('http://localhost/users?page=1#foo');
url.getRelativePath(false, true);
// Output : /users#foo
// The first boolean is "withQuery" and the seconde is "withFragment"
// With query params and fragment :
url.getRelativePath(true, true);
// Output : /users?page=1#foo
Define fragment without hash
url.setFragment('bar');
Retrieve fragment
const fragment = url.getFragment();
// Output : bar
url.getRelativePath(false, true);
// Output : /users#bar
It's possible to merge path and query params with another url
const url = UrlBuilder.createFromUrl('http://localhost:3000').addPath('groups');
const anotherUrl = new UrlBuilder()
.addPath(':id/users', { id: 2 })
.addQueryParam('page', 1)
url.mergePathWith(anotherUrl).toString() // Get 'http://localhost:3000/groups/2/users?page=1'
Note : This function merge only path, params and query params with current url.
Get parent URL easly.
This function return a new instance of UrlBuilder
const url = UrlBuilder.createFromUrl('http://localhost:8080/orders/:orderId/products/:productId');
const parent = url.getParent(); // Get 'http://localhost:8080/orders/:orderId/products'
Or up to the specific level
url.getParent(3); // Get 'http://localhost:8080/orders'
Retrieve the relative path as string format
const postId = 'a937b39e-9664-404a-ac56-f3da2b83a951';
const url = UrlBuilder.createFromUrl('http://localhost:8080/posts/:id').addParam('id', postId);
url.getRelativePath(); // Output: '/posts/a937b39e-9664-404a-ac56-f3da2b83a951'
And with query params
Don't forget to add 'true' parameter to allow query params conversion
url.addQueryParam('displaySimilar', true);
url.getRelativePath(); // Output: '/posts/a937b39e-9664-404a-ac56-f3da2b83a951'
url.getRelativePath(true); // Output: '/posts/a937b39e-9664-404a-ac56-f3da2b83a951?displaySimilar=true'
Retrieve the query params as string format
const queryParams = UrlBuilder.createFromUrl('http://localhost:8080/vehicles').getQueryParams().setAll({
page: 2,
order: 'ASC',
});
queryParams.toString(); // Output: '?page=2&order=ASC'
Retrieve the query params as string format
const name = 'url-builder';
const url = UrlBuilder.createFromUrl('https://github.com/InnovA2')
.addPath(':name/pulls')
.addParam('name', name);
url.toString(); // Output: 'https://github.com/InnovA2/url-builder/pulls'
Compare the current URL to another URL (UrlBuilder instance)
const id = '434f65eb-4e5f-4b29-899c-b3e159fff61c';
const id2 = '3e972ca2-b422-4ac9-b793-e6f305c7bfb2';
const url = UrlBuilder.createFromUrl('http://localhost:8080/users/:id').addParam('id', id);
const url2 = UrlBuilder.createFromUrl('http://localhost:8080/users/:id').addParam('id', id);
const url3 = UrlBuilder.createFromUrl('http://localhost:8080/users/:id').addParam('id', id2);
url.compareTo(url2); // Output: true
url.compareTo(url3); // Output: false
Compare the path segments of the current URL to another relative path
const url: UrlBuilder = UrlBuilder.createFromUrl('/users/10/comments');
url.compareToPathBySegment('/users/10/comments') // Output: true
const url2: UrlBuilder = UrlBuilder.createFromUrl('/users/:id/comments');
url2.compareToPathBySegment('/users/10/comments') // Output: false
const url3: UrlBuilder = UrlBuilder.createFromUrl('/users/:id/comments').addParam('id', 10);
url3.compareToPathBySegment('/users/10/comments') // Output: true
// Or, validate unfilled params
const url4: UrlBuilder = UrlBuilder.createFromUrl('/users/:id/comments');
url4.compareToPathBySegment('/users/10/comments', true) // Output: true
const url = UrlBuilder.createFromUrl('http://localhost:8080/users/10/comments');
url.getBetween2Segments('users', 'comments'); // Output: 10
const url2 = UrlBuilder.createFromUrl('http://localhost:8080/users/10/comments/5');
url2.getBetween2Segments('users', '5'); // Output: 10/comments
Split path string by slash
UrlUtils.splitPath('/InnovA2/url-builder/pulls/'); // Output: ['InnovA2', 'url-builder', 'pulls']
// or if you have more slashes
UrlUtils.splitPath('/InnovA2///url-builder/pulls/'); // Output: ['InnovA2', 'url-builder', 'pulls']
Trim path string by removing useless slashes
UrlUtils.trimPath('/InnovA2/url-builder/pulls/'); // Output: 'InnovA2/url-builder/pulls'
// or if you have more slashes
UrlUtils.trimPath('/InnovA2///url-builder/pulls/'); // Output: 'InnovA2/url-builder/pulls'
Parse filename to create file object containing 'name' and 'ext' (extension). Works with any extension (no verification).
UrlUtils.parseFile('image.png'); // Output: { name: 'image', ext: 'png' }
type ParamType = string | number | boolean;
type ParamFindPredicate = (value: [string, ParamType], index: number, obj: [string, ParamType][]) => boolean;
interface FileInterface {
name: string;
ext: string;
}
static createFromUrl(url: string, defaultBase?: string, isFile?: boolean): UrlBuilder;
copy(): UrlBuilder;
compareTo(url: UrlBuilder, relative?: boolean): boolean;
compareToPathBySegment(path: string, validateUnfilledParams?: boolean): boolean;
getScheme(): Scheme;
setScheme(scheme: Scheme): this;
getHost(): string;
setHost(host: string): this;
getPort(): number;
setPort(port: number): this;
getPathSegments(): string[];
setPathSegments(segments: string[], params?: Record<string, ParamType>): UrlBuilder;
addPath(path: string, params?: Record<string, ParamType>): UrlBuilder;
getPathParams(): PathParams;
setPathParams(params: PathParams): this;
getQueryParams(): QueryParams;
setQueryParams(query: QueryParams): this;
setFilename(filename: string): this;
setFile(file: IFile): this;
getFile(): IFile;
getFragment(): string;
setFragment(fragment: string): this;
mergePathWith(url: UrlBuilder): this;
getFirstPathSegment(): string;
getFirstPath(): string;
getLastPathSegment(): string;
getLastPath(): string;
getParent(n?: number): UrlBuilder;
getBetween2Segments(a: string, b: string): string | null;
getRelativePath(withQuery?: boolean, withFragment?: boolean): string;
toString(): string;
Note : Only the non-static getParent() method return new instance of UrlBuilder. Others update and return the current instance.
constructor(baseUrl?: UrlBuilder, entries?: readonly (readonly [string, ParamType])[] | null);
getAll(): { [key: string]: ParamType };
add(key: string, value: ParamType): this;
addAll(params: Record<string, ParamType>): this;
setAll(params: Record<string, ParamType>): this;
deleteBy(predicate: ParamFindPredicate): this;
getBaseUrl(): UrlBuilder;
filter(predicate: ParamFindPredicate): PathParams;
constructor(baseUrl?: UrlBuilder, entries?: readonly (readonly [string, ParamType])[] | null);
getAll(): { [key: string]: ParamType };
add(key: string, value: ParamType): this;
addAll(params: Record<string, ParamType>): this;
setAll(params: Record<string, ParamType>): this;
deleteBy(predicate: ParamFindPredicate): this;
getBaseUrl(): UrlBuilder;
filter(predicate: ParamFindPredicate): QueryParams;
toString(): string;
splitPath(path: string): string[];
trimPath(path: string): string;
parseFile = (filename: string): FileInterface;
Do not hesitate to participate in the project! Contributors list will be displayed below.