- RETS client for NodeJS
rets-client
provides an interface to log in and retrieve data from a RETS server.
Inspired by:
Spec is based on https://www.nar.realtor/retsorg.nsf/retsproto1.7d6.pdf and https://www.reso.org/rets-specifications/.
- get metadata
- search
The Client constructor takes the login URL and a settings object.
new Client(loginUrl: string, options: object)
Setting | Required | Description |
---|---|---|
headers | No | An object of custom headers to use in the RETS requests. |
password | Yes* | The RETS password. *Required if userAgentPassword is not used. |
product | Yes | The name of the software product that is interfacing with the RETS server. This is used to create the User-Agent header. |
productVersion | No | The product version for the software product that is interfacing with the RETS server. This is used to create the User-Agent header. |
retsVersion | Yes | The version of RETS to use. |
username | Yes* | The RETS username. *Required if userAgentPassword is not used. |
userAgentPassword | No | The password value to use if the RETS server requires user agent authentication. |
import Client from '@aptuitiv/rets-client';
const clientSettings = {
username: 'myUserName',
password: 'myPassword',
headers: {
'Custom-Header': 'headerValue'
},
product: 'YourProductName',
retsVersion: 'RETS/1.7.2',
};
const client = new Client('https://retsdomain.com/path/Login', clientSettings);
.login(): Promise<boolean>
.logout(): Promise<boolean>
client.login()
.then(() => {
// Do something here.
// Log out
client.logout()
.catch((error) => {
console.error('Error logging out: ', error);
})
})
.catch((error) => {
console.error('Error logging in: ', error);
});
Alternately, you could use await
.
try {
await client.login();
// Do something here
// Log out
await client.logout();
} catch (error) {
console.error(error);
}
The login
method will return a Promise. The resolved value is true
.
The logout
method will return a Promise. The resolved value is true
.
When getting objects you have the choice to get one object, multiple objects, or all of the objects for a resource.
.getObject(resourceType: string, type: string, resourceId: string|number, objectId: string|number): Promise<object>
This will retrieve and return a single object.
Where getObjects returns an array of objects, this will return a single object. Even if multiple objects are retrieved, only the first object is returned.
Name | Type | Description |
---|---|---|
resourceType | string | The resource type. For example, "Property" |
type | string | The object type. Example: "Photo" or "Thumbnail" |
resourceId | string or number | The ids of the objects to retrieve combined with the resource id. |
objectId | string or number | The identifier for the object. |
The getObject
method will return a promise. The resolved value is an object containing the retrieved object.
{
contentType: string,
data: Buffer or string,
headers: object
}
Name | Type | Description |
---|---|---|
contentType | string | The value of the Content-Type header. |
data | Buffer or object | If the object is a media type like an image then the value is a Buffer. If the returned object is XML then this will be a JSON representation of that XML. |
headers | object | An object containing all of the headers in the response. The header names are normalized to lowercase. The key is the header name. The value is the header value. |
If the object has already been retrieved recently the RETS server may return an XML response indicating that nothing has changed since the last request.
client.getObject('Property', 'Thumbnail', parts[3], parseInt(parts[4], 10))
.then((objects) => {
if (!objects.contentType.includes('xml')) {
const writeStream = fs.createWriteStream(parts[4]);
writeStream.write(objects.data, 'base64');
}
client.logout()
.then(() => {
console.log('LOGGED OUT');
})
.catch((error) => {
console.log('error logging out');
});
})
.catch((error) => {
console.log('error getting image: ', error);
})
.getObjects(resourceType: string, type: string, ids: string|string[]|object): Promise<object[]>
Name | Type | Description |
---|---|---|
resourceType | string | The resource type. For example, "Property" |
type | string | The object type. Example: "Photo" or "Thumbnail" |
ids | string, array, or object | The ids of the objects to retrieve combined with the resource id. |
options | object | Configuration for getting objects |
The ids
value is a combination of the resource id and the identifier for the object to return For example, with images, it's typically the image number to return. "3" would refer to the third image. [3, 5] would refer to the third and fifth images.
The ids
value can be set in a few different ways.
For the examples below we will use 1234567890
for the resource id and 3
for the object id. In this case it'll be the image id for the third image.
In each case the resource id should be a string. If it's a number and it's large like most resource ids are, then it may get interpreted by Javascript as an exponent.
- string: In this case only the single object that matches the identifier will be returned. It should be in this format:
RESOURCE_ID:OBJECT_ID
. For example1234567890:3
. - "*": This is a special string value that tells the RETS server to return all of the object type for the resource. It should be in this format:
RESOURCE_ID:*
. For example'1234567890:*'
. - array: This should be an array
RESOURCE_ID:OBJECT_ID
pairs. This will retrieve the objects that match the ids. For example:['1234567890:1', '1234567890:2', '1234567890:3']
. - object: This format is also for retrieving multiple objects. The key for is the resource id. The value could be a single object id, an array of object ids, or
*
. The resource id does not have to be the same value.
Below are some examples of how the object
format could be used.
Single object id
{
RESOURCE_ID:OBJECT_ID
}
{
'1234567890':3
}
{
'1234567890':1,
'1234567890':2,
'1234567890':3
}
Array of object ids:
{
RESOURCE_ID:[OBJECT_ID, OBJECT_ID]
}
{
'1234567890':[3,4,5],
'2222244444':[1,2,3]
}
All objects with *
{
RESOURCE_ID:*
}
{
'1234567890':'*'
}
The following values are available for the options
parameter.
Name | Type | Description |
---|---|---|
location | integer | Whether to include the location (URL) data for the object only. 0 or 1. Defaults to 0. If 1, then only the URL for the object will be returned. |
mime | string | The mime type to accept. This is used to build out the Accept header. If not set then */* is used. |
The getObjects
method will return a promise. The resolved value is an array containing the data for one or more retrieved objects.
[
{
contentType: string,
data: Buffer or string,
headers: object
}
]
Name | Type | Description |
---|---|---|
contentType | string | The value of the Content-Type header. |
data | Buffer or object | If the object is a media type like an image then the value is a Buffer. If the returned object is XML then this will be a JSON representation of that XML. |
headers | object | An object containing all of the headers in the response. The header names are normalized to lowercase. The key is the header name. The value is the header value. |
If the object has already been retrieved recently the RETS server may return an XML response indicating that nothing has changed since the last request.
import fs from 'fs';
client.getObjects('Property', 'Photo', {
'10190712134022552561000000':[1,2,3,4,5],
'10190602181039375284000000':'7',
'10190808180154120205000000':8
})
.then((objects) => {
if (Array.isArray(objects)) {
objects.forEach((object) => {
if (!object.contentType.includes('xml')) {
console.log('write to: ', `${object.headers['object-id']}.jpg`);
const writeStream = fs.createWriteStream(`${object.headers['object-id']}.jpg`);
writeStream.write(object.data, 'base64');
}
});
}
client.logout()
.then(() => {
console.log('LOGGED OUT');
})
.catch((error) => {
console.log('error logging out');
})
})
.catch((error) => {
console.log('error getting image: ', error);
})
Images are a specific type of object that you can get. There are two helper functions to make it a little easier to get images.
getImage
: Get a single imagegetImages
: Get one or more images.
.getImage(resourceType: string, imageType: string, resourceId: string|number, imageNumber: string|number): Promise<object>
If you are only going to get a single image then it is recommended to use getImage
. This will return an object with the image data.
Name | Type | Description |
---|---|---|
resourceType | string | The resource type. For example, "Property" |
imageType | string | The image type. Example: "Photo" or "Thumbnail" |
resourceId | string or number | The ids of the objects to retrieve combined with the resource id. |
imageNumber | string or number | The identifier for the image. |
The getImage
method will return a promise. The resolved value is an object containing the retrieved image.
{
contentType: string,
data: Buffer or string,
headers: object
}
Name | Type | Description |
---|---|---|
contentType | string | The value of the Content-Type header. |
data | Buffer or object | If the object is a media type like an image then the value is a Buffer. If the returned object is XML then this will be a JSON representation of that XML. |
headers | object | An object containing all of the headers in the response. The header names are normalized to lowercase. The key is the header name. The value is the header value. |
If the image has already been retrieved recently the RETS server may return an XML response indicating that nothing has changed since the last request.
import fs from 'fs';
client.getImage('Property', 'Photo', '2013823934923493249324', '2')
.then((image) => {
if (!image.contentType.includes('xml')) {
const writeStream = fs.createWriteStream('my-image.jpg');
writeStream.write(object.data, 'base64');
}
})
Alternately, you could use await
.
import fs from 'fs';
try {
const image = await client.getImage('Property', 'Thumbnail', '2013823934923493249324', '2');
if (!image.contentType.includes('xml')) {
const writeStream = fs.createWriteStream('my-image.jpg');
writeStream.write(object.data, 'base64');
}
} catch (error) {
console.error(error);
}
.getImages(resourceType: string, imageType: string, resourceId: string|number, imageNumber: string|number|string[]|number[]): Promise<object[]>
The getImages
method lets you get one or more images.
Name | Type | Description |
---|---|---|
resourceType | string | The resource type. For example, "Property" |
type | string | The object type. Example: "Photo" or "Thumbnail" |
resourceId | string or number | The ids of the objects to retrieve combined with the resource id. |
imageNumber | string, number, array | The identifiers of the images to retrieve. |
The imageNumber
parameter could be in the following format:
- string:
'3'
- *number':
3
- *array':
['3', '4']
or[3, 4, 5]
, or[3, '10', 11]
*
to indicate all images for the resource.
The getImages
method will return a promise. The resolved value is an array containing the data for one or more retrieved objects.
[
{
contentType: string,
data: Buffer or string,
headers: object
}
]
Name | Type | Description |
---|---|---|
contentType | string | The value of the Content-Type header. |
data | Buffer or object | If the object is a media type like an image then the value is a Buffer. If the returned object is XML then this will be a JSON representation of that XML. |
headers | object | An object containing all of the headers in the response. The header names are normalized to lowercase. The key is the header name. The value is the header value. |
If the image has already been retrieved recently the RETS server may return an XML response indicating that nothing has changed since the last request.
import fs from 'fs';
client.getImages('Property', 'Photo', '2013823934923493249324', [1, 2, 3, 4, 5])
.then((images) => {
images.forEach((image) => {
if (!image.contentType.includes('xml')) {
const writeStream = fs.createWriteStream(`${image.headers['object-id']}.jpg`);
writeStream.write(image.data, 'base64');
}
});
})
Alternately, you could use await
.
import fs from 'fs';
try {
const images = await client.getImages('Property', 'Photo', '2013823934923493249324', [1, 2, 3, 4, 5]);
images.forEach((image) => {
if (!image.contentType.includes('xml')) {
const writeStream = fs.createWriteStream(`${image.headers['object-id']}.jpg`);
writeStream.write(image.data, 'base64');
}
});
} catch (error) {
console.error(error);
}
The tests are located in the test
folder. They can be run with npm run test
.