cogGraphQL API to expose the XWiki model for usecases where REST is too verbose or produces too much back and forward between the client and the server.
TypeJAR
Category
Developed by

Eduard Moraru, Simon Urli

Active Installs0
Rating
0 Votes
LicenseGNU Lesser General Public License 2.1
Compatibility

XWiki 12.6+

Installable with the Extension Manager

Description

This is currently a proof of concept and should not be used in production or on a wiki with user rights set. The extension will not check user rights.

Inspiration: https://github.com/phillip-kruger/graphql-example

It follows the Eclipse MicroProfile GraphQL API Specifications using the SmallRye GraphQL Implementation. It uses the code-first approach, rather than the schema-first traditional approach, and extracts the schema from the annotated model classes and methods defined in the code.

The API is accessible through the /graphql endpoint, implemented using the XWiki Reference API

The generated schema can be obtained by getting the following URL:

http://localhost:8080/xwiki/graphql/schema.graphql

A very basic query (in this case, the title and content for the Main.WebHome document) can be done by using curl:

curl -X POST -H "Content-Type: application/json" -d '{"query": "{ document(documentReference: \"Main.WebHome\") { title, content }}"}' http://localhost:8080/xwiki/graphql

One recommended client for experimenting with the API inside your browser would be the Altair Firefox add-on.

For the initial version (proof of concept), the following classes are manually indexed and are part of the accessible API:

org/xwiki/contrib/graphql/GraphqlApi.class
com/xpn/xwiki/api/Document.class
com/xpn/xwiki/api/Attachment.class
com/xpn/xwiki/api/Object.class
com/xpn/xwiki/api/Property.class
com/xpn/xwiki/api/Class.class
com/xpn/xwiki/api/Collection.class

Future versions should automatically read indexes that are precomputed at build time (using the jandex maven plugin) and deployed with the extension that wants to extend the sparql model when it is installed. The XWiki model should also provide such an index, thus removing the need for the above manual mapping.

Queries

Examples of currently supported basic CRUD queries:

  • Get (only) the specified document fields, objects and attachments:
    {
      document(documentReference: "Sandbox.WebHome") {
        title
        author
        creationDate
        contentUpdateDate
        syntax
        content
        objects {
          reference
        }
        attachmentList {
          filename
          date
        }
      }
    }
    • Output:
      {
        "data": {
          "document": {
            "title": "Sandbox",
            "author": "XWiki.superadmin",
            "creationDate": "2020-07-31T17:12:50",
            "contentUpdateDate": "2020-07-31T17:12:50",
            "syntax": "XWiki 2.1",
            "content": "The sandbox is a part of your wiki that you can freely modify. It's meant to let you practice editing. You will ...",
            "objects": [],
            "attachmentList": [
              {
                "filename": "XWikiLogo.png",
                "date": "2020-07-31T17:12:50"
              }
            ]
          }
        }
      }
  • Get all documents, but only the specified fields:
    {
      documents {
        documentReference
        pageReference
        title
        author
      }
    }
    • Output:
      {
        "data": {
          "documents": [
            {
              "documentReference": "xwiki:WikiManager.Translations",
              "pageReference": "xwiki:WikiManager/Translations",
              "title": "Translations",
              "author": "XWiki.superadmin"
            },
            {
              "documentReference": "xwiki:XWiki.DocumentTreeTranslations",
              "pageReference": "xwiki:XWiki/DocumentTreeTranslations",
              "title": "Document Tree Translations",
              "author": "XWiki.superadmin"
            },
            {
              "documentReference": "xwiki:XWiki.Notifications.Code.EmailJobClass",
              "pageReference": "xwiki:XWiki/Notifications/Code/EmailJobClass",
              "title": "EmailJobClass",
              "author": "XWiki.superadmin"
            },
            {
              "documentReference": "xwiki:AppWithinMinutes.TextArea",
              "pageReference": "xwiki:AppWithinMinutes/TextArea",
              "title": "$services.localization.render('platform.appwithinminutes.classEditorTextAreaFieldName')",
              "author": "XWiki.superadmin"
            },
      ...
  • Mixing both individual and all documents requests within the same query:
    {
      document(documentReference: "Main.WebHome") {
        title
        author
        creationDate
        contentUpdateDate
        syntax
        content
      }
      documents {
        title
      }
    }
    • Output:
      {
        "data": {
          "document": {
            "title": "Home",
            "author": "XWiki.superadmin",
            "creationDate": "2020-07-31T17:13:06",
            "contentUpdateDate": "2020-07-31T17:13:06",
            "syntax": "XWiki 2.1",
            "content": "{{box cssClass=\"floatinginfobox\"}}\n{{velocity}}\n{{html clean=\"false\"}}\n## ..."
          },
          "documents": [
            {
              "title": "Translations"
            },
            {
              "title": "Document Tree Translations"
            },
            {
              "title": "EmailJobClass"
            },
      ...
  • Create or update a document:
    mutation {
      createOrUpdateDocument(
        documentReference: "Sandbox.NewDocument"
        title: "Document Title"
        content: "Hello2!"
      ) {
        documentReference
      }
    }
    • Output:
      {
        "data": {
          "createOrUpdateDocument": {
            "documentReference": "xwiki:Sandbox.NewDocument"
          }
        }
      }
  • Delete a document:
    mutation {
      deleteDocument(documentReference: "Sandbox.NewDocument") {
        documentReference
      }
    }
    • Ouput:
      {
        "data": {
          "deleteDocument": {
            "documentReference": "xwiki:Sandbox.NewDocument"
          }
        }
      }

More details on the current API and the supported queries and mutations can be found either in the above mentioned generated schema, or in the code.

Current Limitations and TODO

  • XWiki dependency issue on XWiki prior 12.10+. Solr is bringing antlr4-runtime-4.5.1-1.jar but we needed 4.7.2 for graphql-java. Installation requires manual steps.
  • Hardcoded model. Use an initializer to dynamically load all annotated classes
  • User authentication does not seem to work with user:[email protected]?basicauth=1. Current user is hardcoded to XWiki.Admin.
  • XWikiDocument contains 2 getters returning void: XWikiDocument.getUniqueLinkedEntityReferences (2 signatures), causing issues when attempted to be queried
  • We can not use @Inject-ed XWiki components inside GraphqlApi since it is annotated with @GraphQLApi and its lifecycle is managed by the graphql library, which is not aware of XWiki components. The only solution is to use Utils.getComponent.

Prerequisites & Installation Instructions

  • Delete the existing antlr4-runtime-4.5.1-1.jar core extension (located in the webapps/xwiki/WEB-INF/libs folder) and replace it with a version greater than or equal to 4.7.2 (as required by the graphql-java dependency). (not needed for 12.10+)
  • Restart XWiki and install the GraphQL API extension.

Dependencies

Dependencies for this extension (org.xwiki.contrib:api-graphql 0.1):

  • org.xwiki.commons:xwiki-commons-component-default 12.4
  • org.xwiki.platform:xwiki-platform-oldcore 12.4
  • org.xwiki.platform:xwiki-platform-query-manager 12.4
  • io.smallrye:smallrye-graphql 1.0.7
  • io.smallrye:smallrye-graphql-schema-builder 1.0.7
  • org.xwiki.platform:xwiki-platform-container-servlet 12.4
  • jakarta.json:jakarta.json-api 1.1.6
  • org.glassfish:jakarta.json 1.1.6
  • jakarta.json.bind:jakarta.json.bind-api 1.0.2
  • org.eclipse:yasson 1.0.7
Tags:
    

Get Connected