Opus, the Latin for ‘work’, is the way in which the pieces of a tilework are cut and placed.
The GraphQL requests generated by this library are easily extensible by the plugin system, because they are generated procedurally, as opposed to the commonly-used generation from strings.
This library is TINY and still provides all of the basic functionality of GraphQL interactions. Additional features are planned to get implemented on-demand.
Generate GraphQL requests with Builder pattern and receive properly structurally typed responses upon fetching!
Almost every aspect of GraphQL functionality is supported: fields, nested fields, inline fragments, arguments. The only thing not yet supported are non-inline Fragments. Although, apart from slightly increased request size, this will not impact your development experience in any way.
import { Query, Field, InlineFragment } from '@tilework/opus';
const dragonFields = ['name', 'neck_length', 'age'] as const;
const dragonsQuery = new Query('dragons', true) // `true` means 'expect array'
.addArgument('limit', 'Int', 5)
.addFieldList(dragonFields)
.addField(new Field('children', true)
.addFieldList(dragonFields)
)
.addField(new InlineFragment('Fire')
.addField('fire_temperature')
)
.addField(new InlineFragment('Ice')
.addField('ice_density')
)
Sometimes it is necessary to explicitly reference the type, which the fetched data will have upon retrieval. A utility type is provided in order to make this possible!
import { Query } from '@tilework/opus';
import type { DataType } from '@tilework/opus';
const query = new Query('person', true)
.addFieldList(['name', 'surname']);
let result: DataType<typeof query>;
result = await client.post(query);
An opportunity to derive additional data from the fetched information is provided with calculated fields. A calculated field can be added on any instance of Field
, Query
or Mutation
.
Such fields get calculated once, when the request is post-processed upon fetching. They are calculated starting with the deepest child and going up to the root node (post-visit).
import { Query, Field } from '@tilework/opus';
const query = new Query('dragons', true)
.addField('active')
.addField(new Field('launch_payload_mass')
.addField('kg')
.addCalculatedField('lb', (result) => result.kg * ONE_KG_IN_LBS)
)
.addField(new Field('return_payload_mass')
.addField('kg')
)
.addCalculatedField('payload_delta_kg', (result) => {
return result.launch_payload_mass.kg - result.return_payload_mass.kg;
});
Note: Attempts to add fields to the result via this API will throw due to the processable object being sealed at the time of processing. Use calculated fields to add additional fields.
Sometimes it's necessary to modify the data you have received, e.g. in order to reduce nesting of some fields. In order to achieve that, this functionality should be used!
In the example below, the property launch_payload_mass
becomes launch_payload_mass.kg
, just to make everything a bit more convenient.
import { Query, Field } from '@tilework/opus';
const query = new Query('dragons', true)
.addField('active')
.addField(new Field('launch_payload_mass')
.addField('kg')
.addTransformation((launchPayload) => launchPayload.kg)
)
.addField(new Field('return_payload_mass')
.addField('kg')
.addTransformation((returnPayload) => returnPayload.kg)
);
...
typeof result.dragons[0].launch_payload_mass; // number
The client
provides an opportunity to fetch queries and mutations, as well as fetch combined queries and combined mutations.
import { client, CombinedField } from '@tilework/opus';
// Single requests
const queryResult = await client.post(someQuery);
const mutationResult = await client.post(someMutation);
// Combined queries and mutations work the same
const combinedQueryResult = await client.post(new CombinedField
.add(firstQuery)
.add(secondQuery)
);
It is necessary to set up the client before fetching any data. See the required configuration steps below.
- Endpoint
client.setEndpoint(endpoint: string)
allows to configure this in runtime- Setting
GRAPHQL_ENDPOINT
inprocess.env
will also set the endpoint - It defaults to
/graphql
- Headers
client.setHeaders(headers: any)
will set the headers to use for fetching requests