Skip to content

fluree/fluree-client

Repository files navigation

@fluree/fluree-client

This is the official Fluree client SDK for TypeScript/JavaScript. It is a wrapper around the Fluree API, providing a more convenient way to interact with Fluree v3 databases.

Tested against the following fluree/server Docker Hub images:

  • fluree/server:5839ffe273062b8da972b120deb54dd62e7c3d1f: Current stable version
  • fluree/server:c452631c50b8f8e595d486240dab503bbaad6033: October 30 2024
  • fluree/server:d5eb31b1c2be560a92a30176dc8b0e01973859ea: October 22 2024
  • fluree/server:60829de035c4996369f7dbe0766b80db0e743a8b: October 4 2024

Installation

npm install @fluree/fluree-client

Usage

Node.js

const { FlureeClient } = require('@fluree/fluree-client');

// Create and connect to a Fluree instance
const client = await new FlureeClient({
  host: 'localhost',
  port: 8090,
  ledger: 'example/ledger',
}).connect();

// Perform a query
const result = await client
  .query({
    select: { '?s': ['*'] },
    where: {
      '@id': '?s',
    },
  })
  .send();

ES Modules (Browser)

import { FlureeClient } from '@fluree/fluree-client';

// Create and connect to a Fluree instance
const client = await new FlureeClient({
  host: 'localhost',
  port: 8090,
  ledger: 'example/ledger',
}).connect();

// Perform a query
const result = await client
  .query({
    select: { '?s': ['*'] },
    where: {
      '@id': '?s',
    },
  })
  .send();

Client Config

The FlureeClient constructor takes an optional config object with the following properties:

{
    isFlureeHosted, // [boolean] If true, the client will use the Fluree hosted service
    apiKey, // [string] The API key to use for the Fluree hosted service
    ledger, // [string] The ledger/db name on the Fluree instance
    // Do not set "host" and "port" if "isFlureeHosted" is true
    host, // [string] The host where your instance is running (e.g. localhost)
    port, // [number] The port where your instance is running (e.g. 58090)
    create, // [boolean] If true, the ledger will be created if it does not exist
    privateKey, // [string] The private key to use for signing messages
    signMessages, // [boolean] If true, messages will be signed by default
    defaultContext, // [object] The default context to use for queries/txns
}

For example:

const client = new FlureeClient({
  ledger: 'fluree-client/client',
  host: 'localhost',
  port: 58090,
  create: true,
  privateKey: 'XXX...XXX',
  signMessages: true,
  defaultContext: {
    schema: 'http://schema.org/',
    name: 'schema:name',
    // ...
  },
});

You can also update the configuration of an existing client by using the configure() method:

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
});

client.configure({
  ledger: 'fluree-jld/387028092978174',
});

Methods

connect()

In order to use the FlureeClient instance, you must first connect to the Fluree instance. This will test the connection and (if config.create === true) create the ledger if it does not exist.

It will also throw an error if the connection fails (e.g. invalid host, ledger does not exist, etc.)

const connectedClient = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

create()

The create() method can be used to create a new ledger on the Fluree instance. This will throw an error if the ledger already exists.

The returned FlureeClient will be configured to use the new ledger.

const client = new FlureeClient({
  host: 'localhost',
  port: 8080,
  ledger: 'fluree-client/client',
});

const createdClient = await client.create('new-ledger');

query()

The query() method creates a new QueryInstance for querying the Fluree database. The QueryInstance can be used & re-used to build, sign, and send queries to the Fluree instance.

See the QueryInstance section for more information.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const queryInstance = client.query({
  select: { freddy: ['*'] },
});

const response = await queryInstance.send();

transact()

The transact() method creates a new TransactionInstance for transacting with the Fluree database. The TransactionInstance can be used & re-used to build, sign, and send transactions to the Fluree instance.

See the TransactionInstance section for more information.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const transactionInstance = client.transact({
  insert: { '@id': 'freddy', name: 'Freddy' },
});

const response = await transactionInstance.send();

delete()

The delete() method creates a new TransactionInstance for deleting subjects by @id in the Fluree database. The TransactionInstance can then be used to sign and send delete transactions to the Fluree instance.

Delete is not an API endpoint in Fluree. This method helps to transform a single or list of subject identifiers (@id) into a where/delete transaction that deletes the subject(s) and all facts about the subject(s).

// Existing data:
// [
//   { "@id": "freddy", "name": "Freddy" },
//   { "@id": "alice", "name": "Alice" }
// ]

const txnInstance = client.delete(['freddy']);

const txnObject = txnInstance.getTransaction();

console.log(txnObject);

//  {
//     where: [{ '@id': 'freddy', ?p0: '?o0' }],
//     delete: [{ '@id': 'freddy', ?p0: '?o0' }],
//     ledger: ...
//   }

const response = await txnInstance.send();

// New data state after txn:
// [
//   { "@id": "alice", "name": "Alice" }
// ]

upsert()

The upsert() method creates a new TransactionInstance for upserting with the Fluree database. The TransactionInstance can be used & re-used to build, sign, and send upsert transactions to the Fluree instance.

Upsert is not an API endpoint in Fluree. This method helps to transform an upsert transaction into an insert/where/delete transaction.

Upsert assumes that the facts provided in the transaction should be treated as the true & accurate state of the data after the transaction is processed.

This means that facts in your transaction should be inserted (if new) and should replace existing facts (if they exist on those subjects & properties).

// Existing data:
// [
//   { "@id": "freddy", "name": "Freddy" },
//   { "@id": "alice", "name": "Alice" }
// ]

const txnInstance = client.upsert([
  { '@id': 'freddy', name: 'Freddy the Yeti' },
  { '@id': 'alice', age: 25 },
]);

const txnObject = txnInstance.getTransaction();

console.log(txnObject);

//  {
//     where: [ { '@id': 'freddy', name: '?1' }, { '@id': 'alice', age: '?2' } ],
//     delete: [ { '@id': 'freddy', name: '?1' }, { '@id': 'alice', age: '?2' } ],
//     insert: [
//       { '@id': 'freddy', name: 'Freddy the Yeti' },
//       { '@id': 'alice', age: 25 }
//     ],
//     ledger: ...
//   }

const response = await txnInstance.send();

// New data state after txn:
// [
//   { "@id": "freddy", "name": "Freddy the Yeti" },
//   { "@id": "alice", "name": "Alice", "age": 25 }
// ]

// Note that if this had been an "insert" freddy would now have two names.
// Note also that if this had been handled by deleting/insert, alice might have lost her name.

history()

The history() method creates a new HistoryQueryInstance for querying the history of the Fluree database. The HistoryQueryInstance can be used & re-used to build, sign, and send history queries to the Fluree instance.

See the HistoryQueryInstance section for more information.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const historyQuery = client.history({
  'commit-details': true,
  t: { at: 'latest' },
});

const response = await historyQuery.send();

generateKeyPair()

Automatically generates a new key pair and adds it to the FlureeClient instance. The public key and DID will be derived from the private key and added to the FlureeClient instance.

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
});

client.generateKeyPair();

const privateKey = client.getPrivateKey();

setKey()

This adds a private key to the FlureeClient instance. This key will be used to sign messages by default when using the sign() method on a query or transaction.

The public key and DID will be derived from the private key and added to the FlureeClient instance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const privateKey = 'XXX...XXX';

client.setKey(privateKey);

const publicKey = client.getPublicKey();
const did = client.getDid();

getPrivateKey()

The getPrivateKey() method returns the private key of the FlureeClient instance (if one has been set).

NOTE: Be careful with this method. It is not recommended to log or expose private keys.

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
});

client.generateKeyPair();

const privateKey = client.getPrivateKey();

getPublicKey()

The getPublicKey() method returns the public key of the FlureeClient instance (if one has been set).

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
});

client.generateKeyPair();

const publicKey = client.getPublicKey();

getDid()

The getDid() method returns the DID of the FlureeClient instance (if one has been set).

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
});

client.generateKeyPair();

const did = client.getDid();

setContext()

The setContext() method sets the default context for the FlureeClient instance. This context will be used for all queries and transactions by default.

Unlike addToContext(), which merges new context elements into any existing context for the client, this method will replace the existing default context entirely.

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
  defaultContext: { schema: 'http://schema.org/' },
});

client.setContext({ ex: 'http://example.org/' });

// client.getContext() === { "ex": "http://example.org/" }

addToContext()

The addToContext() method adds to the default context for the FlureeClient instance. This context will be used for all queries and transactions by default.

If a default context already exists, the new context will be merged with the existing context.

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
  defaultContext: { schema: 'http://schema.org/' },
});

client.addToContext({ ex: 'http://example.org/' });

// client.getContext() === {
//  "schema": "http://schema.org/",
//  "ex": "http://example.org/"
// }

getContext()

The getContext() method returns the default context for the FlureeClient instance (if one has been set).

const client = new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
  defaultContext: { schema: 'http://schema.org/' },
});

const context = client.getContext();

// context === { "schema": "http://schema.org/" }

QueryInstance

The QueryInstance class is used to build, sign, and send queries to the Fluree instance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const queryInstance = client.query({
  select: { freddy: ['*'] },
});

const signedQueryInstance = queryInstance.sign('XXX...XXX');

const response = await signedQueryInstance.send();

Additional Methods:

send()

The send() method sends the query to the Fluree instance and returns the response.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const queryInstance = client.query({
  select: { freddy: ['*'] },
});

const response = await queryInstance.send();

sign()

The sign() method signs the query with the private key of the FlureeClient instance. If no private key has been set, or if no privateKey parameter is passed to sign(), it will throw an error.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

let signedQueryInstance = client
  .query({
    select: { freddy: ['*'] },
  })
  .sign('XXX...XXX');

// or

client.generateKeyPair();

signedQueryInstance = client
  .query({
    select: { freddy: ['*'] },
  })
  .sign();

const response = await signedQueryInstance.send();

getQuery()

The getQuery() method returns the query object of the QueryInstance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
  defaultContext: { ex: 'http://example.org/' },
}).connect();

const queryInstance = client.query({
  select: { 'ex:freddy': ['*'] },
});

const query = queryInstance.getQuery();

console.log(query);
// {
//   "@context": { "ex": "http://example.org/" },
//   from: 'fluree-client/client',
//   select: { "ex:freddy": ['*'] }
// }

getSignedQuery()

The getSignedQuery() method returns the signed query of the QueryInstance in the form of a JWS string.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

client.generateKeyPair();

const queryInstance = client.query({
  select: { freddy: ['*'] },
});

const signedQueryInstance = queryInstance.sign();

const signedQuery = signedQueryInstance.getSignedQuery();

console.log(signedQuery);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZWxlY3QiOnsiZnJlZGR5IjpbIioiXX0sImZyb20iOiJmbHVyZWUtY2xpZW50L2NsaWVudCJ9.QNTXpZCQXsbO9zoOtMHT4yH-OqAaNq8ezhV5k7C_BuI

TransactionInstance

The TransactionInstance class is used to build, sign, and send transactions to the Fluree instance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const transaction = client.transact({
  insert: { '@id': 'freddy', name: 'Freddy' },
});

const signedTransaction = transaction.sign('XXX...XXX');

const response = await signedTransaction.send();

Additional Methods:

send()

The send() method sends the transaction to the Fluree instance and returns the response.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const transaction = client.transact({
  insert: { '@id': 'freddy', name: 'Freddy' },
});

const response = await transaction.send();

sign()

The sign() method signs the transaction with the private key of the FlureeClient instance. If no private key has been set, or if no privateKey parameter is passed to sign(), it will throw an error.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

let signedTransaction = client
  .transact({
    insert: { '@id': 'freddy', name: 'Freddy' },
  })
  .sign('XXX...XXX');

// or

client.generateKeyPair();

signedTransaction = client
  .transact({
    insert: { '@id': 'freddy', name: 'Freddy' },
  })
  .sign();

const response = await signedTransaction.send();

getTransaction()

The getTransaction() method returns the transaction object of the TransactionInstance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const transaction = client.transact({
  insert: { '@id': 'freddy', name: 'Freddy' },
});

const txn = transaction.getTransaction();

console.log(txn);
// {
//   ledger: 'fluree-client/client',
//   insert: { '@id': 'freddy', name: 'Freddy' }
// }

getSignedTransaction()

The getSignedTransaction() method returns the signed transaction of the TransactionInstance in the form of a JWS string.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

client.generateKeyPair();

const transaction = client.transact({
  insert: { '@id': 'freddy', name: 'Freddy' },
});

const signedTransaction = transaction.sign();

const signedTxn = signedTransaction.getSignedTransaction();

console.log(signedTxn);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbnNlcnQiOnsiQGlkIjoiZnJlZGR5IiwibmFtZSI6IkZyZWRkeSJ9LCJsZWRnZXIiOiJmbHVyZWUtY2xpZW50L2NsaWVudCJ9.SNHjlNricJbATF06mbrvnqunfV7l2gZHyvj7zYFTby0

HistoryQueryInstance

The HistoryQueryInstance class is used to build, sign, and send history queries to the Fluree instance.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const historyQuery = client.history({
  'commit-details': true,
  t: { at: 'latest' },
});

const response = await historyQuery.send();

send()

The send() method sends the history query to the Fluree instance and returns the response.

const client = await new FlureeClient({
  isFlureeHosted: true,
  apiKey: process.env.FLUREE_API_KEY,
  ledger: 'fluree-jld/387028092978173',
}).connect();

const historyQuery = client.history({
  'commit-details': true,
  t: { at: 'latest' },
});

const response = await historyQuery.send();

Running tests

Before running tests, you'll need a .env.local file in the root of the project. This file needs to contain the following:

TEST_NEXUS_LEDGER="fluree-jld/387028092978318"
TEST_API_KEY="_DPu2OWxmJ-zRwnzNr8uL...5mfV1OsfOXcRmb35t02rp1gMxxSw"

Run tests

In the root of the project, run:

yarn test

Examples

The repository includes complete example projects demonstrating usage in both Node.js and browser environments.

Running the Node.js Example

# Navigate to the Node.js example directory
cd examples/nodejs-example

# Install dependencies (including local fluree-client)
npm install

# Run the example
npm start

Running the Browser Example

# Navigate to the browser example directory
cd examples/browser-example

# Install dependencies (including local fluree-client)
npm install

# Start the development server
npm start

This will open your default browser to the example page. Click the "Run Query" button to execute the example operations.