0.2.0 • Published 2 years ago

@aptuitiv/rets-client v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

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/.

TODO

  • get metadata
  • search

Initialize the RETS client object

The Client constructor takes the login URL and a settings object.

new Client(loginUrl: string, options: object)

Settings

SettingRequiredDescription
headersNoAn object of custom headers to use in the RETS requests.
passwordYes*The RETS password. *Required if userAgentPassword is not used.
productYesThe name of the software product that is interfacing with the RETS server. This is used to create the User-Agent header.
productVersionNoThe product version for the software product that is interfacing with the RETS server. This is used to create the User-Agent header.
retsVersionYesThe version of RETS to use.
usernameYes*The RETS username. *Required if userAgentPassword is not used.
userAgentPasswordNoThe 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);

Logging in and logging out

.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);
}

login() return data

The login method will return a Promise. The resolved value is true.

logout() return data

The logout method will return a Promise. The resolved value is true.

Getting objects

When getting objects you have the choice to get one object, multiple objects, or all of the objects for a resource.

Get a single object

.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.

getObject() Parameters

NameTypeDescription
resourceTypestringThe resource type. For example, "Property"
typestringThe object type. Example: "Photo" or "Thumbnail"
resourceIdstring or numberThe ids of the objects to retrieve combined with the resource id.
objectIdstring or numberThe identifier for the object.

getObject() return value

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
}
NameTypeDescription
contentTypestringThe value of the Content-Type header.
dataBuffer or objectIf 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.
headersobjectAn 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.

getObject() example

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);
    })

Get multiple objects

.getObjects(resourceType: string, type: string, ids: string|string[]|object): Promise<object[]>

getObjects() Parameters

NameTypeDescription
resourceTypestringThe resource type. For example, "Property"
typestringThe object type. Example: "Photo" or "Thumbnail"
idsstring, array, or objectThe ids of the objects to retrieve combined with the resource id.
optionsobjectConfiguration for getting objects

ids

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 example 1234567890: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':'*'
}

options

The following values are available for the options parameter.

NameTypeDescription
locationintegerWhether 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.
mimestringThe mime type to accept. This is used to build out the Accept header. If not set then */* is used.

getObjects() return value

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
    }
]
NameTypeDescription
contentTypestringThe value of the Content-Type header.
dataBuffer or objectIf 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.
headersobjectAn 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.

getObjects() example

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);
    })

Getting images

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 image
  • getImages: Get one or more images.

Get a single image

.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.

getImage() Parameters

NameTypeDescription
resourceTypestringThe resource type. For example, "Property"
imageTypestringThe image type. Example: "Photo" or "Thumbnail"
resourceIdstring or numberThe ids of the objects to retrieve combined with the resource id.
imageNumberstring or numberThe identifier for the image.

getImage() return value

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
}
NameTypeDescription
contentTypestringThe value of the Content-Type header.
dataBuffer or objectIf 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.
headersobjectAn 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);
}

Get multiple images

.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.

getImages() Parameters

NameTypeDescription
resourceTypestringThe resource type. For example, "Property"
typestringThe object type. Example: "Photo" or "Thumbnail"
resourceIdstring or numberThe ids of the objects to retrieve combined with the resource id.
imageNumberstring, number, arrayThe 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.

getImages() return value

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
    }
]
NameTypeDescription
contentTypestringThe value of the Content-Type header.
dataBuffer or objectIf 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.
headersobjectAn 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.

getImages() example

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);
}

Testing

Tests use Mocha and Chai.

The tests are located in the test folder. They can be run with npm run test.