Copyright (C) 2017-2022 The Open Library Foundation
This software is distributed under the terms of the Apache License, Version 2.0. See the file "LICENSE" for more information.
mod-graphql
is a FOLIO module, written in Node.js, that provides a GraphQL service by HTTP POST to /graphql/
. It can be interrogated using any GraphQL client library, such as Apollo, and the graph it provides is auto-generated from the API description files (RAML and JSON Schema) of the modules that it's providing the GraphQL API for.
Using GraphQL instead of the individual modules' low-level RESTful WSAPIs makes it possible to link between different kinds of API object using rich structured queries such as the following, which finds bibliographic instances of books with "baby" in the title, and returns them along with the associated holdings statements and the barcodes of the individual items in each holding:
query {
instance_storage_instances(query: "title=baby") {
totalRecords
instances {
title
holdingsRecords2 {
callNumber
holdingsItems(limit: 20) {
barcode
}
}
}
}
}
Each link-field generated in the schema is implemented by the resolver as a sub-query to a FOLIO service, and can accept an optional limit
argument specifying the largest number of records the subquery should fetch (default: 10), as in the holdingsItems
sub-query above.
It's the usual drill for an NPM module. First, install dependencies:
$ yarn install
Then run the tests:
$ yarn test
You can start mod-graphql
using yarn start
, providing as additional command-line arguments the paths to one or more RAML files that describe the APIs to be provided via GraphQL. For example:
yarn start ../mod-inventory-storage/ramls/instance-storage.raml
The module's functioning is affected by several environment variables, as detailed below, so in practice a more typical invocation might be:
env OKAPI_URL=https://folio-snapshot-okapi.dev.folio.org LOGCAT=listen,url yarn start tests/schemas-for-tests/mod-inventory-storage/ramls/instance-storage.raml
The simplest way to exercise the running module is by using folio-graphiql
, a browser-based client for querying with GraphQL. See that module's documentation for details, and consult Example GraphQL queries for some ways to get started.
In addition to the main mod-graphql
module, a commandline program raml2graphql
is provided, which translates a set of RAML files, together with their referenced JSON Schemas, into a GraphQL schema which is emitted on standard output. The RAML files to be translated are provided as command-line arguments; further options can be seen by running raml2graphql
with no arguments.
Instead of listing all the RAML files to be handled on the command-line, it's possible to start mod-graphql
in mode that begins by reading an API file that lists the RAMLs of the modules that are to be included. To do this, use the -a
command-line options, followed the path to an API file, like this:
env RAML_DIR=.. RAML_SKIP=1 OKAPI_URL=http://localhost:9130 LOGCAT=listen,url yarn start -a api.yml
When started in this mode, mod-graphql
assembles the list of RAMLs from the specified API file, and this assembly process is affected by the values of several evironment variables described below:
RAML_DIR
,
RAML_SKIP
and
RAML_MATCH
.
API files are written in YAML, and are described in the FOLIO document How to configure the generation of API documentation. The FOLIO project maintains A master API file describing the RAMLs of all the core FOLIO modules: the simplest way to create an API file for given installation of mod-graphql
may be to copy that file and remove the parts that are not needed.
The operation of mod-graphql
is affected by several environment variables:
These are used in the standard way, as with for example the Okapi command-line client:
OKAPI_URL
: specifies the URL of the Okapi service which is contacted in order to perform the underlying WSAPI operations needed to respond to GraphQL queries. When not specified, the Okapi URL is determined from theX-Okapi-URL
header in the requests that are sent tomod-graphql
, i.e. low-level WSAPI requests are sent to the same Okapi that sent the high-level GraphQL request. Typical value:http://localhost:9130
.OKAPI_TENANT
: specifies the name of a FOLIO tenant enabled for the specified Okapi service, which is used for all WSAPI operations. When not specified, each outgoing request uses the tenant specified by the incoming request that caused it. Typical value:diku
.OKAPI_TOKEN
: used to provide the value of a token from an established Okapi session associated with the specified tenant. When not specified, each outgoing request uses the token specified by the incoming request that caused it. Typical value:eyJhbGciOiJIUzUx...v76BSXSlPh-m9AQA
.
If these are not explicitly set in the environment, their values are taken from a .env
file in the working directory, if that file exists.
See Run mod-graphql in the host box for the required use of the OKAPI_URL
environment variable when running Okapi inside a VM and mod-graphql outside it.
Required only when regenerating test tapes. This is the URL of an Okapi instance which the yakbak library should proxy for, providing the Okapi service from which WSAPI tapes are made.
A comma-separated list of options, each of which can affect the operation of mod-graphql
in various ways:
allowSchemaless
-- when set, endpoints that define no schema are simply ignored, rather than throwing an error. This is useful when working with an incompletely specified RAML file, such as one to which the JSON Schemas are being added progressively.ignoreSchemaMapsWithInlineSchemas
-- mod-graphql does not support parsing of schema maps when one or more of the schemas is inclued inline in the RAML rather than pulled in from an external file. Usually the existence of an inline schema is a fatal error, but when this option is set it instead causes the schema-map to be empty. This should only be used when running the test suite.ignoreRamlWarnings
-- By default, any error or warning in parsing a RAML file or its associated JSON Schemas results in an immediate exit with exit-value 2. When this option is set, an exit is caused only by errors, not by warnings. Necessary for some non-lint-clean RAMLs.
Choose which categories of logging you want to see by running with the LOGGING_CATEGORIES
environment variable set to comma-separated list of categories. The following are supported (listed here in the order that that they occur during a run):
skip
-- log names of RAML files that are skipped from the API list due to their not being present on the filesystem.nomatch
-- log names of RAML files that are omitted from the API list due to their not matching the specified regular expression.exclude
-- log names of RAML files that are excluded from the API list due to their matching the specified regular expression.nomulti
-- log names of RAML file sections that are omitted from the API list due to their havingmultiple: true
in their specification.ramllist
-- log the names of the RAML files generated from the API list.ramlpath
-- log the paths of the RAML files to be loaded.endmap
-- log when the list of schemas parsed from a RAML reaches an unexpected end.schemamap
-- log the RAML file's implied map from top-level schema identifiers to their directories.raml
-- log the RAML file as initially loaded, before conversion to a GraphQL schema begins.nojson
-- log WSAPI endpoints in the RAML for which there is no JSON body specification. Such endpoints are not necessarily errors, and are skipped in translating the RAML, but may indicate an incomplete specification.notype
-- log names of fields that have no specified JSON type but are inferred by the presence of a$ref
to be objects.unknowntype
-- log uses of unknown basic types.schema
-- log when a schema is registered, and just before trying to read a schema file.replace
-- log when a JSON Schema is encountered for the second or subsequent time, as the code declines to replace the first version.duptype
-- log when merging schemas results in a duplicate defintion of a type, but the definition is the same in both cases. (It is a hard error if two different definitions are given for the same type.)api
: log a JSON rendition of the gathered API specification. Useful for debugging. Or, more specifically:api.comments
: log a JSON rendition of only thecomments
portion of the gathered API specification.api.resources
: log a JSON rendition of only thecomments
portion of the gathered API specification.api.types
: log a JSON rendition of only thecomments
portion of the gathered API specification.
schema
-- log the generated GraphQL schema before starting to execute it.listen
-- log when the serve is about to start listening.failsub
-- log a resolver's failure to substitute an argument or field-value into a path.url
-- log each WSAPI URL before trying to fetch it.result
-- log the result of each GET.resultcount
-- log only the count (totalRecords
) in the result of each GET.skeleton
-- log the "skeleton" used to extract the relevant part of each result, and the part thus extracted.
For convenience, the abbreviated environment-variable name LOGCAT
may be used instead of LOGGING_CATEGORIES
, with the same effect.
When driving mod-graphql
from an API file, that file will specify the relative locations of the various modules' RAML files. The RAML_DIR
environment variable specifies what directory they are to be interpreted relative to. For example, if mod-graphql
is checked out alongside the various modules that it will be providing services for, RAML_DIR=..
will allow an API-file reference to the mod-inventory-storage
module's ramls
directory, containing a file holdings-storage
, to be interpreted as pertaining to
../mod-inventory-storage/ramls/holdings-storage.raml
.
When driving mod-graphql
from an API file, RAML files that are referenced from the API file but do not exist in the filesystem cause a fatal error. If RAML_SKIP
is set to a non-zero value, such files are simply skipped (and the fact is logged using the skip
category).
When driving mod-graphql
from an API file, the selection of RAML files can be limited to only those that match a regular expression specified by the RAML_MATCH
environment variable. For example, RAML_MATCH='^mod-(inventory.*|users)$'
will use only the RAML files from the mod-inventory
, mod-inventory-storage
and mod-users
modules.
When driving mod-graphql
from an API file, the selection of RAML files can be trimmed by omitting those that match a regular expression specified by the RAML_EXCLUDE
environment variable. For example, RAML_EXCLUDE='^raml'
will omit the RAML files from the raml
and raml-module-builder
modules.
When set to a true value (e.g. 1
), causes every output to the console to be accompanied by a full stack-trace. This can be useful when tracking down the cause of a warning.
If you are getting this warning all over your output:
[DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
You can get rid of it by run Node with the with --no-deprecation
command-line option. The simplest way to do this is to set NODE_OPTIONS=--no-deprecation
.
Other documentation for users of mod-graphql
:
- The change-log for this module.
- Documentation on using GraphQL from Stripes
- Example GraphQL queries that this module can run.
Documentation for developers of the module:
- Developing with the Vagrant box
- Recording tests
- Documentation of the schema/resolver auto-generation code, including the JSON Schema extensions for link-fields.
- Documentation of the intermediate in-memory representaton of a compiled API, only of interest to mod-graphql developers.
- How to remove running modules from a FOLIO installation: useful if you need to substitute your own in-development module. This is an important document, but should be part of core FOLIO documentation, not part of mod-graphql.
Also:
folio-graphiql
, a graphical client for exploring the data that can be returned by mod-graphql. Useful for testing and demos.
Other modules are described, with further FOLIO Developer documentation at dev.folio.org
See project MODGQL at the FOLIO issue tracker.