Skip to content
Vitaly Tomilov edited this page Apr 7, 2021 · 118 revisions

How to use special symbols for user name or password?

User name, password, path or parameters - all need to be URL-encoded. When in doubt, just run this:

console.log(encodeURIComponent('my-password'));

Some popular special symbols that need to be encoded:

  • # = %23
  • @ = %40
  • % = %25
  • ^ = %5E
  • ? = %3F
  • + = %2B
  • = = %3D
  • , = %2C
  • / = %2F
  • < = %3C
  • > = %3E
  • | = %7C

Other special symbols, such as ~ or $, for example, can be, but do not need to be encoded.

Note that all non-Latin letters need to be encoded.

Is there a simpler way to access the first host name + port?

The library supports host, hostname, port + type for that, as documented within Virtual Properties.

// when supporting multiple hosts:
const host = cs.hosts?.[0].toString();
const hostname = cs.hosts?.[0].name;
const port = cs.hosts?.[0].port;
const type = cs.hosts?.[0].type;

// when supporting only one host, the above code can be simplified to this:
const {host} = cs; // = cs.hosts?.[0].toString()
const {hostname} = cs; // = cs.hosts?.[0].name
const {port} = cs; // = cs.hosts?.[0].port
const {type} = cs; // = cs.hosts?.[0].type

How to get the full host name properly?

When hosts is set, each element in the array is an object that has method toString, to generate the full host name:

const cs = new ConnectionString('test://first,second:123');

const firstHost = cs.hosts?.[0].toString(); // = first = cs.host

const secondHost = cs.hosts?.[1].toString(); // = second:123

And for the first host, there is even simpler approach - property host.

Do not use something like ${cs.hostname}:${cs.port}, which would incorrectly produce first:undefined.

See also the encoding options that method toString can accept.

How to use a file path in URL directly?

If your protocol allows an alternative syntax of a file path, in place of regular connection details, the recommended approach is to make the distinction via an optional extension (sub-protocol), like -file, for example, and then use the path section of the URL for the file path:

const cs = new ConnectionString('protocol-file:///some/file/path/file-name.txt');

// cs.protocol = 'protocol-file'

const [protocol, ext] = cs.protocol?.split('-') ?? []; // split protocol from extension

if(ext === 'file') {
    console.log(cs.path?.join('/'));
    //=> some/file/path/file-name.txt
}

And it will work the same for a relative path:

const cs = new ConnectionString('protocol-file:///../..some/file/path/file-name.txt');

console.log(cs.path?.join('/'));
//=> ../..some/file/path/file-name.txt
  • Protocol can also contain +, : and . as alternative separators.
  • Any space in the file path must be encoded either as %20 or as +.

How can I specify a Unix-socket host?

Any host name that either ends with .sock or contains /, after decoding, is recognized as a Unix socket, with the host's type property set to socket after parsing.

Note that in a socket name inside URL, every symbol / must be encoded as %2F.

// cs - our ConnectionString

// check if the first host is a Unix socket:
const isSocket = cs.type === HostType.socket; // checking type of the first host
// full syntax:
// const isSocket = cs.hosts?.[0].type === HostType.socket;

// or you can compare it to a string:
const isSocket = cs.type === 'socket';
// full syntax:
// const isSocket = cs.hosts?.[0].type === 'socket';

How to access user name + password as URL-encoded?

Q: The type of server that I'm using, natively supports URL-encoded user and password, so I don't want those decoded, I want them exactly as they are in the connection string. How can I do this?

A: URL encoding/decoding is a symmetric operation, i.e. you can simply re-encode those parameters when needed, using the global encodeURIComponent function:

const cs = new ConnectionString(/* your connection string here */);

const encodedUser = cs.user ? encodeURIComponent(cs.user) : '';
const encodedPassword = cs.password ? encodeURIComponent(cs.password) : '';

Alternatively, you can double-encode those, and then no extra work will be needed.


Can I pass in a complex type as a URL parameter?

Yes, you can pass in anything, but after parsing such value will be a string, so you need to apply JSON.parse to it, as shown in the example below.

import {ConnectionString} from 'connection-string';

const s1 = new ConnectionString('test://', {
    params: {
        // passing in a complex value:
        value: [123, true, 'hello', {hi: 'there'}]
    }
});

const connection = s1.toString();
//=> test://?value=123,true,hello,%7B%22hi%22%3A%22there%22%7D

// the reverse operation:
const s2 = new ConnectionString(connection);

// parsing all the values to their original type:
s2.params.value[0] = Number(s2.params.value[0]); // for number
s2.params.value[1] = Boolean(s2.params.value[1]); // for boolean
s2.params.value[3] = JSON.parse(s2.params.value[3]); // for JSON-object

console.log(s2.params.value);
//=> [123, true, 'hello', {hi: 'there'}]

How to pass arrays of values?

The library supports standard comma-separated list of values that you can assign to a parameter, which automatically turns the property into an array of the corresponding values:

const cs = new ConnectionString('?val=one,two');

//=> { params: { val: [ 'one', 'two' ] } }

And it also supports repeated-parameter syntax, accumulating all values into parameter-array:

const cs = new ConnectionString('?val=one,two&val=three,four');

//=> { params: { val: [ 'one', 'two', 'three', 'four' ] } }

The syntax is symmetric, which means that setting params: {val: [1, 2, 3]} in the connection object will serialize it into a comma-separated list:

const cs = new ConnectionString('', {
    params: {
        val: [1, 2, 3]
    }
});

console.log(cs.toString());
//=> ?val=1,2,3

Note that if your text-values contain commas, those need to be encoded as %2C, to avoid being mistaken for value separators.