CRAFTS: Configurable REST APIs For Triple Stores

Massive amounts of Linked Open Data are readily available to anyone who wants to use them. Unfortunately, Semantic Web technologies such as SPARQL and RDF remain unfamiliar to the majority of web developers, more used to REST APIs. This paper addresses the challenge of accessing Linked Open Data through REST APIs. Configurable REST APIs For Triple Stores (CRAFTS) is the tool devised for this purpose. CRAFTS allows knowledge engineers to configure REST APIs over multiple triple stores. CRAFTS automatically handles the translation of API calls into SPARQL queries, delivering results in JSON format. Web developers can then use a CRAFTS API to read and write Linked Open Data. The API of CRAFTS is uniform, domain-independent, and described with the OpenAPI specification. A reference implementation of CRAFTS is published in a GitHub repository, and a live test site is readily available since February 2021. CRAFTS is currently employed in eight different applications, with more than 2.4K users, and more than 260K API calls.


I. Introduction
With the embracement of the Linked Data principles [1], [2], a data deluge is available across all domains. This is especially evident through the evolution of the Linked Open Data (LOD) cloud from 12 datasets in 2007 to 1,301 in 2021. 1 While there are different ways of accessing LOD [3], SPARQL querying has widespread adoption among Semantic Web practitioners. Unfortunately, SPARQL has a very steep learning curve, is error-prone, and tedious, even for experts [4], [5].
Web developers are not familiar with Semantic Web technologies such as SPARQL, RDF, and OWL. Instead, they are used to Representational State Transfer (REST) [6] Application Programming Interfaces (APIs) and the JavaScript Object Notation (JSON) data interchange format [7]. Therefore, the challenge for the Semantic Web community is how to make accessible the LOD cloud to web developers. Ideally, they should employ regular REST APIs that allow them to read and write Linked Open Data from multiple triple stores and using JSON for data exchanges. There are several proposals of API generators for Linked Open Data, notably RAMOSE [4], OBA [8], grlc [9], and BASIL [10]. However, they do not comply with all the aforementioned requirements.
In this paper, this challenge is addressed with the proposal of CRAFTS, a tool that can be configured to access Linked Open Data through REST APIs. Contributions include: • A uniform API for managing CRAFTS APIs, sending parametrized SPARQL queries, and performing read and write operations over RDF resources (Section III-B). • An architecture with the logical components of CRAFTS for providing the desired functionalities (Section III-C). • A reference implementation of CRAFTS, available in a GitHub repository. A working test site of CRAFTS is also included (Section III-D). • A showcase scenario (Section IV) and a brief description of the main applications that currently exploit CRAFTS (Section V). • A discussion of CRAFTS and its relationship to other competing approaches (Section VI). The rest of the paper is organized as follows: Section II analyses existing approaches for accessing LOD, particularly API generators. Section III provides a technical description of CRAFTS, including its requirements, a description of the API of CRAFTS, its logical architecture, and implementation details. Section IV presents a showcase scenario. Section V reports about the uptake of CRAFTS so far. Section VI includes a discussion. The paper ends with a conclusion and future work lines in Section VII.

II. Related work
Access to LOD is challenging even for knowledge engineers. Beyond expertise with W3C standards such as RDF and SPARQL, accessing LOD requires familiarity with the ontologies employed to annotate data, as well as some domain knowledge (not trivial in many specialized domains). Due to this, the Semantic Web community has proposed several approaches to facilitate the access to triple stores. Some proposals define an HTTP interface over Linked Data, notably Linked Data Platform [11] and Linked Data Fragments [3]. The Linked Data Platform is a W3C recommendation for providing read and write access to Linked Data resources. The main focus is on describing resource representations with triples, but its application to a non-RDF model such as JSON is not covered. Linked Data Fragments is a framework that defines so-called Triple Pattern Fragments for consuming Linked Data in an efficient way. Triple Pattern Fragments can be used as a limited Linked Data API that provides read-only access to RDF resources that returns triples.
Other approaches propose new serializations of Linked Data and SPARQL results to JSON such as JSON-LD [12] and SPARQL transformer [13]. JSON-LD is a syntax to serialize Linked Data in JSON format. JSON-LD is especially relevant for publishers, since it provides a way to convert an RDF graph into JSON. SPARQL transformer proposes a new JSON serialization of SPARQL results in order to simplify the output, but it does not support SPARQL query formulation, a much more demanding task for web developers.
Web developers commonly employ REST APIs and JSON as the main interchange format [14]. It is thus desirable to provide a similar solution for accessing LOD. There are several proposals in the literature that support the creation of REST APIs on top of triple stores: RAMOSE [4], grlc [9], BASIL [10], and OBA [8]. To facilitate their comparison, I will employ the following set of desirable features of API generators for LOD: • Generic approach: an API generator should provide a domain independent solution for the provision of REST APIs over LOD sources. • Flexible configuration of REST APIs: an API generator should allow a high degree of control in the specification of an API. • Ontology-driven API generation: an API can be configured by using an ontology as input. • Expose RDF resources: an API can provide access to RDF resources through HTTP methods [15]. • Support read operations: an API can provide read access to exposed RDF resources through HTTP GET calls. • Support write operations: an API can provide write access to exposed RDF resources with operations such as POST, PUT, or DELETE. • Support partial updates: an API can provide partial updates to exposed RDF resources through HTTP PATCH calls. • Support parametrized queries: an API can provide a way to specify input parameters for submitting parametrized SPARQL queries. • Use JSON as interchange format: an API should use JSON to format body requests and responses. • Caching SPARQL queries: an API can cache responses from triple stores to limit network exchanges. • OpenAPI documentation: an API can be documented with the OpenAPI specification [16]. • Access to multiple endpoints: an API can access one or several endpoints. Table I summarizes the features of the surveyed API generators for LOD. All of them offer generic approaches for the creation of REST APIs and employ JSON as interchange format. RAMOSE, grlc, and BASIL essentially allow the provision of APIs that encapsulate parametrized SPARQL queries. In this way, knowledge engineers will define the queries to be supported, and web developers will make API calls instead of authoring SPARQL queries. However, none of them allow the exposition of RDF resources over an API -this is why the flexibility of these tools is considered "Low".
In contrast to the previous proposals, OBA is mainly purposed for exposing RDF resources over REST APIs. OBA employs an ontology as input to automatically generate an API for a single target endpoint. The ontology is analyzed to extract the classes and properties in order to create an OpenAPI specification for the API. OBA employs a series of predefined query templates to map API calls into SPARQL queries. Read and write operations are supported since OBA maps GET, POST, PUT, and DELETE requests to CONSTRUCT, INSERT, UPDATE, and DELETE SPARQL queries, respectively; however, partial updates are not supported. OBA generates one-toone mappings between an API call and a SPARQL query. The simplicity of this translation facilitates the automatic generation of an API from an ontology, but flexibility is somewhat reduced, basically allowing the retrieval of the datatype and object properties of RDF resources. OBA can also accommodate parametrized SPARQL queries, requiring a knowledge engineer to author them.
All the surveyed proposals except RAMOSE support OpenAPI documentation. None of them use caching to limit exchanges with triple stores. Moreover, they do not provide access to multiple endpoints from an API.  This analysis serves to identify a group of API generators (RAMOSE, grlc, and BASIL) providing a basic functionality that is limited to the exposition of parametrized SPARQL queries. On a next step, OBA also allows the exposition of RDF resources -supporting read and write operations-, as well as ontology-driven API generation that can be appealing in some situations. However, there are cases that require additional features, such as enhanced flexibility in the specification of an API, support for partial updates, caching SPARQL queries, and access to multiple triple stores.

III. Technical description of CRAFTS
Configurable REST APIs For Triple Stores (CRAFTS) is a novel tool for accessing LOD through REST APIs. As graphically depicted in Figure 1, different types of users are involved. LOD users are interested in accessing Linked Open Data, but they require appropriate applications in order to fulfil their user goals. Web developers are programmers that develop applications for the World Wide Web. They commonly use REST APIs and JSON, but are not fluent in Semantic Web technologies. Web developers can employ a CRAFTS API by submitting regular REST calls without requiring knowledge of RDF, OWL, or SPARQL. Craftsmen are knowledge engineers that are in charge of setting up CRAFTS APIs. Once configured, an API provides transparent access to one or several endpoints - Figure 1 shows that API A is configured to access endpoints #0 and #1; API B accesses endpoints #1 and #2; and API C just accesses endpoint #3-. CRAFTS automatically handles the translation of API calls into SPARQL queries, delivering results in JSON format.

A. Requirements
CRAFTS is designed to fulfil the requirements in Table II. CRAFTS should allow the provision of REST APIs on top of SPARQL endpoints in a domain-agnostic way (R0). The mechanism for configuring an API should be very flexible (R1), allowing a high degree of control of Access to multiple endpoints the data to expose through the API. Once configured, a CRAFTS API should work as a plain REST API. RDF resources will be accesible at specific URLs through HTTP methods (R2). A CRAFTS API should allow read operations, i.e. HTTP GET, over RDF resources (R3), but also write operations such as PUT or DELETE (R4). Write operations imply the modification of RDF data in a triple store, typically supported through SPARQL Update [17]. Partial updates will be also supported through HTTP PATCH (R5). A CRAFTS API should also support parametrized SPARQL queries (R6). The aim is twofold: (1) to discover IRIs of RDF resources that can be accessed through the API, and (2) to provide a simple way of querying an endpoint without requiring knowledge of SPARQL. API body requests and responses in CRAFTS will be formatted in JSON (R7). Since API calls will propagate into SPARQL queries to the source endpoints, queries will be cached to limit future exchanges with the endpoints (R8). CRAFTS will be documented with the Open-API specification [16] (R9), a standard and programming language-agnostic interface description for REST APIs. Adhering to OpenAPI seems a sensible decision, given that OpenAPI is the most popular specification for REST APIs, with the largest community, and the best tooling [14]. Finally, CRAFTS will allow the configuration of APIs that transparently access one or several endpoints if desired (R10).

B. The API of CRAFTS
In order to comply with the requirements in Table II, CRAFTS provides a uniform API that is summarized in Table III. This API is documented with the OpenAPI specification, as required (R9). Thus, the API of CRAFTS will be described using the terminology defined in Open-API.
A REST API supports a number of different calls, each one includes a path and an operation. A path identifies a web resource exposed by the API; it is defined with a URL relative to the server. An operation is one of the HTTP methods that will be applied to the target resource such as GET, PUT, DELETE. . . A call can be further qualified with different types of parameters. A path parameter is a variable part of the URL that is denoted with curly braces { }; when a client makes an API call, any path parameter has to be substituted with an actual value. Query parameters appear at the end of the request URL after a question mark ?, with different name=value pairs separated by ampersands &. Write operations (POST, PUT, and PATCH) typically require a request body with the representation of the web resource to create or update. An API call will return a response consisting of an HTTP status code and an optional response body -the latter is especially relevant for read operations through GET-. Schemas are used to define the structure of request and response bodies.
API calls C0-3 in Table III are aimed for the management of CRAFTS APIs. The design of this block is relatively straightforward: call C0 serves to obtain the list of available APIs, while the remaining calls C1-3 refer to a specific CRAFTS API by using the path parameter apiId. More importantly, a CRAFTS API configuration has to be provided in the request body of call C2 so as to create or replace a CRAFTS API through a PUT operation [15]. Any valid configuration has to follow the schema in Figure 2. Specifically, a configuration is a JSON object with the following keys and values: • apiId: the identifier of the API. It has to be unique for a CRAFTS site. • endpoints: an array of SPARQL endpoints that serve Linked Open Data for the API. Every endpoint requires an identifier and a SPARQL URI. Further access information can be included such as a graph URI, authentication credentials, or SPARQL Update activation. • model: an array of resource models that guides data exchanges with the endpoints. Every request for an RDF resource with the API (calls C4-8) must reference a resource model with an identifier id. A resource model defines a mapping of RDF data to a JSON object: datatype properties are specified in dprops, object properties in oprops, and class membership in types. As for the required parameters, label will be the key in the mapped JSON object, endpoint refers to the source of data, and iri identifies the corresponding datatype or object property. The rest of parameters are optional and will be illustrated in Section IV. • queryTemplates: an array of SPARQL query templates. Each one has an id, a previously configured endpoint, an array of parameters, an array of variables, and a template. The latter is a Mustache 2 template that must produce a valid SPARQL query after replacing the template placeholders with the parameters. The array of variables have to coincide with the projected variables from the SPARQL query.    Table III are used for easily accessing Linked Open Data. They all have the same overall structure, valid for any successfully configured API in CRAFTS: path parameter apiId identifies the API, query parameter id refers to a resource model, and query parameter iri identifies the target RDF resource. The operation determines whether it will be retrieved (GET), created or replaced (PUT), updated (PATCH), or deleted (DELETE). Resource representations will be exchanged in request and response bodies, as required by the operation. They will be all formatted in JSON following the schema defined in the corresponding resource model. As for partial updates of resources (call C6), JSON PATCH [18] is used to express the sequence of operations to apply to the target RDF resource. Since C8 allows the retrieval of a set of RDF resources in a single call, it can be used to reduce the number of C4 calls.
Finally, C9 is purposed for easily sending parametrized SPARQL queries, as well as for discovering IRIs of RDF resources to be used in calls C4-8. The Appendix includes a non-trivial CRAFTS API configuration object, while Section IV presents a thorough showcase scenario that exploits such API configuration.

C. Architecture
The logical architecture of CRAFTS is graphically depicted in Figure 3. Incoming calls are first checked if they comply with the specification in Table III. Valid calls are dispatched to the API manager, the component in charge of the management of the APIs in CRAFTS. Depending on the call type, the API manager may rely on other components in order to produce an answer. Specifically, the API manager can handle by itself calls C0, C1, and C3, corresponding to list, read, and delete operations of existing APIs in CRAFTS. Every call with a request body (C2, C5, and C6) is forwarded to the Model Validator to check the correctness of the included data. RDF resource read operations (C4 and C8) and parametrized queries (C9) are handled by the Data manager. Calls C5, C6, and C7 are RDF resource write operations and are processed by the Resource updater. Figure 4 shows the flowcharts of a representative set of the calls supported by CRAFTS (C2, C4, C5, and C9).
The Model validator is used to detect errors in the request bodies of the received calls. Note that syntactic errors in request bodies are detected upfront due to the use of JSON schema validation. Instead, this component focuses on higher-level problems. In the case of call C2 (see Figure 4a), the API configuration provided in the request body is thoroughly analyzed to check wrong references to endpoints, duplicate ids and labels, and wrong references to model elements. Moreover, all the endpoints are tested with probe queries, including triple insertions and deletions if a sparqlUpdate configuration is present, as well as test queries for every resource model and query template included in the configuration. With respect to calls C5 and C6, the Model Validator checks whether the provided request bodies are compliant with the corresponding model element in the API configuration.
The Data manager handles all data exchanges with the endpoints. Regarding resource read calls (C4 and C8), the Data manager will map those requests into SPARQL queries and return JSON data in response (see Figure 4b).
The target model element of the API drives this data extraction process. As for the types array, a SPARQL query will be created for each element in this array using the Mustache template in Listing 1 with the iris of the request and the inferred and restrictions values of the model type element, if included. Similarly, the Mustache template in Listing 2 will be used for the dprops, and oprops arrays of the model element. Answers to these queries are stored in the Data cache, so as to limit the requests to the endpoints. In this way, the Data manager first checks the Data cache before querying an endpoint. With respect to call C9 (see Figure 4c), the Data manager first identifies the target query template in the API configuration, and constructs the actual query with the received parameters. The Data cache is, again, first checked for an answer hit before querying the endpoints. The Resource updater handles resource writing calls (C5, C6, and C7). As a first step for any of these calls, the Resource updater makes a resource read request to the Data   Figure 4d). Upon arrival of the corresponding JSON object, the Resource updater will prepare a sequence of graph update operations in the endpoints that will be dispatched to the Data manager. In the case of a resource deletion (C7), the obtained JSON object will be analyzed to obtain the triples to be removed in the target endpoints through DELETE DATA operations. For a fresh resource creation (C5), the request body is used to produce the triples to be included in the target endpoints through INSERT DATA operations. In the case of a resource replacement (C5 too), existing triples will be removed and then the new ones will be inserted. Regarding call C6, the strategy is somewhat different to comply with the atomicity requirement of PATCH requests [19]: (1) the operations of the patch are sequentially applied to a copy of the obtained JSON object; (2) if the sequence is valid, the Resource updater compares the two JSON objects and obtains the triples to be deleted and inserted in the endpoints; and (3) the corresponding graph update operation is dispatched to the Data manager. For any writing call, the Resource updater keeps track of the RDF resources that were modified and makes a clean cache request to the Data manager.
D. Implementation I have coded a full functional version of CRAFTS in JavaScript for the popular Node.js platform. 3 The code is organized in several files that reflect the logical architecture in Figure 3. The implementation effort has been considerably reduced by the integration of a number of Node.js libraries. Notably, CRAFTS uses the Express.js 4 web framework to easily handle web requests. The whole API of CRAFTS (see Table III) is annotated with the OpenAPI specification [16]. This is exploited by the express-openapi-validator 5 to perform a syntactic validation of incoming calls, again simplifying the code of CRAFTS. The OpenAPI specification of CRAFTS is also used to provide an auto-generated API documentation served with Swagger UI Express. 6 The utility functions of Underscore 7 are employed for handling JavaScript collec-tions. Mustache 8 is used for templating SPARQL queries, as described in Section III-C. A configuration file is used to adjust parameters such as the port of the Node.js server or the timespan of cached elements.
The source code of CRAFTS is available on GitHub. 9 I have also set up a live version of CRAFTS 10 for anyone who wants to use it. The OpenAPI specification of CRAFTS is browsable (and actionable) at this URL. 11 This version provides two authentication schemes: Basic [20] and Bearer authentication [21]. Basic authentication is aimed to craftsmen, although anybody with a valid email account can sign up (an email will be sent for activating the user). A registered user -typically a craftsman-can then use their credentials to make any call to CRAFTS through the Basic authentication scheme. A user will be authorized to make any call to an API of their own, e.g. updating the API (C2) or reading a resource (C4). A user will only be authorized to make read calls (C1, C4, and C8-9) of others' APIs, but they will not be allowed to make write calls (C2-3 and C5-7) of others' APIs.
The Bearer authentication scheme is aimed for web developers to access a CRAFTS API without requiring user registration. Every API includes read and write tokens that are only shown to the owner of the API through call C1. The read token of an API can be used to make calls C4 and C8-9 with Bearer authentication, while the write token can be used to make calls C4-9.

IV. Showcase of CRAFTS
This section illustrates the capabilities of CRAFTS in a showcase scenario. It will be demonstrated with the test site of CRAFTS 12 , although any other deployment can be used. Table IV includes the namespaces employed along this showcase.
a) Creation of a CRAFTS API: Any registered user can create an API by using call C2 with a configuration in the body request. I will use the configuration included in the Appendix. Briefly, it includes two endpoints: crossforest and dbpedia. The former is a large forestry dataset (almost 200M triples) built in the context of the EU Cross-Forest project 13 with institutional repositories from Spain and Portugal. The latter endpoint is the wellknown English DBpedia [22]. The configuration includes a model with four different elements: Tree, Position, Species, and DbpediaSpecies. There is also a query template, treesinbox. Since the id of the API in the configuration is test, the URL of this PUT call should be https://crafts.gsic.uva.es/apis/test As described in Section III-C, the Model Validator will check that the configuration is correct, including probe queries to crossforest and dbpedia. b) Submitting a parametrized query: Once the API test is set up, I can use the query template treesinbox, aimed for discovering trees of a specific species in a bounding box. For this showcase I will use the parameter values in Table V. Call C9 is purposed for parametrized queries, so the resulting URL will be https://crafts.gsic.uva.es/apis/test/query? id=treesinbox&lngwest=-6&lngeast=-3&latnorth=40& latsouth=37&limit=5&species=https://datos.iepnb.es/ def/sector-publico/medio-ambiente/ifn/Species43 This request is processed by the Data manager that first obtains the query template treesinbox from the API configuration. Next, the Data manager prepares a JSON object with the query parameters enclosed in the URL (species, lngwest, lngeast, latnorth, latsouth, and limit). The Mustache library is then called with the query template and the parameter object, obtaining the SPARQL query in Listing 3. Note that all the parameters of treesinbox are optional, so this query template uses sections such as {{#latsouth}} FILTER (?tlat > {{latsouth}}) {{/latsouth}} to check the existence of a latsouth key in the parameter object and then include the text embedded in the section, substituting latsouth with the value of latsouth in the parameter object, i.e. FILTER (?tlat > 37). Since treesinbox is linked to the crossforest endpoint, the Data manager will first check if there is a hit of this query for crossforest in the Data cache. In case of a miss, the Data manager will submit the query to the crossforest endpoint. Query results will be returned using the standard serialization of SPARQL results in JSON format [23]. 13 https://crossforest.eu/ For the sake of readability, the actual answer to the query in Listing 3 is presented in Table VI.
Listing 3: SPARQL query obtained after applying parameters in Table V  c) Requesting a resource (one endpoint): I will use the first result in Table VI to make an RDF resource read call (C4) for tree:10-2898-A-1-2 and model Tree. The resulting URL is https://crafts.gsic.uva.es/apis/test/ resource?id=Tree&iri=https://datos.iepnb.es/recurso/ sector-publico/medio-ambiente/ifn/tree/05-0810-A- [4][5][6][7][8][9][10][11] This request is received by the Data manager. This component will then use the Tree model to send a series of SPARQL queries to the crossforest endpoint (provided there are misses in the Data cache). Table VII shows the actual SPARQL queries that will be produced after applying the Mustache templates in Listing 1 and 2 to each element in the types, dprops, and oprops arrays of Tree. While the queries are straightforward, it is interesting to note the inclusion of restrictions in species and position (check the origin of those restrictions in the Appendix). Also note that the latter two queries are referred to a different RDF resource, pos:10-2898-A-1-2-23030-4326. This is for embedding position data in the requested tree, as defined in position by setting embed=true and targetId=Position. 14 With the obtained responses, the Data manager will return the JSON object in Listing 4.
14 Species data can be also embedded in a tree by setting embed=true in the species element of the types array. This will result on new queries, specifically the ones in Table VIII to produce Listing 5. Listing 4: Answer to the resource request with id=Tree and iri=tree:10-2898-A-1-2.

d) Requesting a resource (two endpoints):
Similarly to the previous case, I can make an RDF resource read call (C4) for ifn:Species43 and model Species. The resulting URL is https://crafts.gsic.uva.es/apis/test/resource?id=Species& iri=https://datos.iepnb.es/def/sector-publico/medioambiente/ifn/Species43 The interesting thing here is that data is coming from two endpoints, as shown in Table VIII. In the Cross-Forest dataset, tree species are linked to resources in other datasets using schema:sameAs. This is exploited in the element dbpedia of the oprops array that embeds data from DbpediaSpecies, as defined in the configuration. dbr:Quercus_pyrenaica is discovered for ifn:Species43, enabling the formulation of queries dbpedia.comment and dbpedia.image. The Data manager integrates all the received answers to produce the JSON object in Listing 5.
Listing 5: Answer to a resource request with id=Species and iri=ifn:Species43.
{ "iri": "https://datos.iepnb.es/recurso/sector-publico/medioambiente/ifn/tree/0", "species": "https://datos.iepnb.es/def/sector-publico/medioambiente/ifn/Species23", "position": { "iri": "https://datos.iepnb.es/recurso/sector-publico/medioambiente/ifn/position/0", "latWGS84": 40, "lngWGS84": 0 } } This can be seen as the reverse of a read resource call. The main focus here is the correctness of the included request body that must adhere to the API model. Thus, the Model validator checks that species and position exist elsewhere in the types, dprops, and oprops arrays of Tree. It also finds that position refers to a Position model with latWGS84 and lngWGS84 in the corresponding dprops array. After this validation, the Resource updater will send a read request for resource tree:0 and model Tree to the Data manager. If the response contains any data, the Resource updater will prepare DELETE DATA operations with the triples to be removed. As this is a fresh resource creation, the Resource updater only needs to produce the set of triples to be inserted. Listing 7 shows the INSERT DATA operation that will be sent. Since all the insertions apply to the crossforest endpoint, a single operation is needed. Also note that multiple RDF resources can be created with a single call -in this case tree:0 and pos:0. [ { "op": "add", "path": "/diameter_mm", "value": 100 }, { "op": "add", "path": "/height_M", "value": 10 } ] Listing 8 is a JSON PATCH that is checked with the Model validator. Since diameter_mm and height_M are defined in the dprops array of Tree and their values are literals, the patch is validated and the request is forwarded to the Resource updater. This component sends a read request for the target resource to the Data manager. Then, it creates a copy of the returned JSON object (see Listing 6) and applies each operation included in the patch. If no errors are found, the Resource updater obtains the triples to be deleted and inserted by comparing the original and the modified JSON objects. In this case there are no removals, so the update is completed with the INSERT DATA operation in Listing 9.
Listing 9: SPARQL Update query to fulfill the request in Listing 8.
INSERT DATA { tree:0 ifn:hasDBH1InMillimeters 100 ; ifn:hasTotalHeightInMeters 10 . } g) Deleting a resource: I conclude the showcase with the deletion of tree:0. This can be done with call C7, again using the URL https://crafts.gsic.uva.es/apis/test/ resource?id=Tree&iri=https://datos.iepnb.es/recurso/ sector-publico/medio-ambiente/ifn/tree/0 No request body is needed here, so the Resource updater can easily handle this call. As in previous resource write operations, it sends a read request for resource tree:0 V. Uptake of CRAFTS The test site of CRAFTS 16 was launched in February 2021. Since then, different projects are using CRAFTS through eight active APIs. Three of them are based on previous works, while the remaining five correspond to new projects based on CRAFTS from the beginning. Activity in the test site is tracked with the Google Analytics platform. 17 Table IX summarizes the collected data (obtained in December 2021). Remarkably, more than 2.4K LOD users have accessed CRAFTS in 6.9K sessions and making 259.7K calls. The bulk of this workload corresponds to three APIs: Forest Explorer (87.5% of all the calls), EducaWood (9.0%), and LocalizARTE (0.7%). There is a dedicated web application for each of these APIs, as described below.
Forest Explorer [24] is a web application that offers an interactive map for browsing forestry data from the Cross-Forest and English DBpedia endpoints. This application was refactored in March 2021 for using a CRAFTS API instead of a custom SPARQL query formulation logic. The refactoring was motivated by (1) major changes in the Cross-Forest ontology and (2) the release of new data (particularly evident with the inclusion of forestry data from Portugal). The CRAFTS API for Forest Explorer includes: three bootstrapping query templates for obtaining all available species, soil usages, and provinces; three additional query templates for discovering patches, plots, and trees in a geographical area; and a model with 11 elements (Tree, Species, Province. . . ). Since I am the developer of the original and the refactored versions of Forest Explorer, it is possible to analyze the impact of using CRAFTS.
The refactoring required a modest effort, two working days, dedicated to replace the custom SPARQL querying code with common REST calls to the new CRAFTS API. More importantly, the refactored version is much simpler, despite the increased complexity in the ontology and the increased size of the Cross-Forest dataset (71GB vs 11GB). A source lines of code (SLOC) analysis of the two versions with CLOC 18 revealed that the CRAFTS version of Forest Explored employs 10.0% SLOC less. Focusing on the component in charge of data exchanges with the endpoints alone, SLOC reduction is 28.8%.
EducaWood [25] is a socio-semantic annotation system intended for environmental learning in Secondary and Higher Education. The CRAFTS API of EducaWood is configured for retrieving land cover maps and forestry data from the Cross-Forest endpoint, as well as species information from the English DBpedia. This API uses a third endpoint to publish annotations of trees and other ecosystem structures such as dead wood and microhabitats. While consumption of forestry data from the Cross-Forest endpoint is similar to the case of Forest Explorer, the creation of social tree annotations is the most distinctive feature of EducaWood.
LocalizARTE [26] is a supporting web application of Casual Learn [27], a ubiquitous learning mobile application in the Cultural Heritage domain. Teachers can use LocalizARTE to annotate sites of interest and educational activities associated to them, e.g. take a photo of the southern rose window of the Cathedral of León. Learners can then use Casual Learn with their mobile devices to carry out educational activities in close proximity. LocalizARTE makes use of a CRAFTS API to reduce the effort required for the creation of Cultural Heritage sites. Specifically, the API uses the English and Spanish DBpedia endpoints, defines two query templates, and includes three elements: Place, Image, and Category. The template queries are purposed for finding the closest sites of interest to a given point. A subsequent resource read call serves to extract the coordinates, label, comment, image, and Wikipedia categories of the found sites. A teacher can reuse all this data when annotating a Cultural Heritage site.
EducaWood and LocalizARTE are developed by two Master students with no expertise in Semantic Web technologies. In these two cases I played the role of craftsman and configured the corresponding CRAFTS APIs. I prepared a short guide for using each API, similar to the showcase in Section IV, but succincter. The students followed the guide and they had no problems in using the APIs to build LocalizARTE and EducaWood (even using the write calls of the API in this latter case).
The majority of LOD users are inadvertently making API calls to CRAFTS through the provided web applications. The distribution of LOD users roughly corresponds to the reported percentages of calls per API. In the case of Forest Explorer, 64% of the users are located in Spain, 10% in Portugal, 3% in United States, and the rest in other countries around the world. As the Cross-Forest dataset includes data from Iberian forests, the majority of users are forestry professionals from Spain and Portugal and outside our contact network -some of them send us feedback by social media and through a web form that is requested to fill after some significant activity in Forest Explorer-. 19 With respect to EducaWood and LocalizARTE, the user base is smaller (~100 users) and more local (mainly Spain), as their promotion is not yet initiated.
To conclude this section, Table X shows the distribution of call types and their average latency in the test site of CRAFTS. The API of Forest Explorer accounts for the immense majority of C8 and C9 calls. Template queries (C9) in Forest Explorer correspond to relatively complex geospatial requests for retrieving features (i.e. patches, plots, and trees) in a bounding box. Isolating the template query for gathering patches, the latency of a fresh request of this type is~1.5 seconds, while cached requests are served in~6 milliseconds. This illustrates that the generation cost of a SPARQL query is negligible compared to the cost of querying an endpoint, thus motivating the use of a cache. C8 calls are very responsive and efficient, given that Forest Explorer tries to pack 100 resources in a single C8 call. The API of EducaWood is responsible for all write resource calls (C5, C6, and C7) with a good latency. Creating or updating an API (C2) is an unfrequent operation, but it is slow. This is because CRAFTS sends SPARQL probes for testing that the API configuration is correct, e.g. 47 queries are sent when creating the API of Forest Explorer.

VI. Discussion
CRAFTS has demonstrated to be very flexible for accessing LOD. When configuring an API, a craftsman has a high degree of control of which data to expose and in which form. The configuration goal should be to provide meaningful data access to LOD users. This implies filtering out unnecessary classes and properties of the sources in the API model. The use of embedding can be very helpful to integrate different RDF subgraphs into a single JSON object. This is quite desirable for web developers so as to 19 More than one week using the application and a session length of more than five minutes.
gather all the data about a resource with a single read call (C4), e.g. Listing 4 illustrates how all the relevant data about a tree, including its position, is obtained with a single API call. In this way, web developers do not need to be aware of the existence of different RDF subgraphs, and the result is a familiar JSON object. Moreover, an API can be configured to seamlessly integrate data from several endpoints; Listing 5 showcases a non-trivial example of species data integration from the Cross-Forest and English DBpedia endpoints.
The flexibility of CRAFTS comes at a price. When producing an API configuration, the craftsman should have sufficient knowledge of the underlying sources so as to ensure that RDF data is mapped to JSON structures as required. Domain experts and web developers should also participate in the creation of an API by identifying which data to extract and in which particular form. In this regard, APIs can be built in an incremental way, testing intermediate versions, and gathering feedback from the different user groups at different stages. Indeed, web developers can skip many details of an API, such as property IRIs and restrictions of models, or the Mustache templates of parametrized queries.
The API of CRAFTS is completely generic, domainagnostic, and predictable. CRAFTS includes a very thorough validation process to assist the creation of API configurations; this is supported through the use of OpenAPI for detecting syntactic errors, as well as through the checks of the Model validator component. The OpenAPI specification is also exploited to expose an interactive frontend of the API contents, 20 As a result, a CRAFTS API can be accessed as any regular REST API. Web developers can easily send parametrized SPARQL queries by selecting a template in an API and setting appropriate parameter values, as demonstrated in Section IV. They will discover IRIs of RDF resources in the obtained answers, enabling the usage of regular REST API calls for reading and writing Linked Open Data resources. The showcase scenario and the APIs introduced in Section V give a glimpse of the versatility of CRAFTS. Noteworthy, two Master students with no training on Semantic Web topics are developing web applications on top of CRAFTS APIs.
Alternatives to CRAFTS (see Section II) also require knowledge engineers to configure APIs. In the case of RAMOSE, grlc, and BASIL, somebody needs to author the parametrized SPARQL queries using custom conventions, while CRAFTS employs Mustache as a well-known templating mechanism. Regarding OBA, the use of an ontology-driven API generator may reduce the need of knowledge engineers for creating APIs, but in practice some customization is needed (as discussed in [8]). Moreover, the scope of an API does not necessarily match the scope of an ontology, e.g. the Forest Explorer API only gathers tree species information from the English DBpedia, so it is impractical to take the whole DBpedia ontology for this purpose.
While OBA and CRAFTS share several features (see Table I), an important difference is that the former employs one-to-one mappings between an API call and a SPARQL query. In contrast, CRAFTS uses one-to-many mappings, as illustrated in Listings 5, and 6; this allows a more granular operation that enables the integration of data from several endpoints -this feature is not currently supported by OBA-. Further, configuring an API model in CRAFTS is not as demanding as authoring SPARQL queries, since the former basically entails the inclusion of datatype and object properties; more fine-grained decisions can be made to support embedding and restrictions, as illustrated in Section IV. Other relevant differences include the native support for caching in CRAFTS and partial updates of resources through PATCH requests.
VII. Conclusion and future work CRAFTS is a tool that allows the provision of REST APIs over LOD. Craftsmen are knowledge engineers that can set up APIs with a high degree of flexibility. CRAFTS APIs can be configured to transparently access multiple triple stores, supporting read and write operations over RDF resources, encapsulating parametrized SPARQL queries, and delivering results in JSON format. Since web developers are already used to REST APIs and JSON, they can employ CRAFTS APIs to access LOD.
Ongoing pilots with CRAFTS demonstrates the usefulness of this tool for supporting the consumption, integration, and generation of LOD. Future work includes the exploitation of CRAFTS in a number of application cases, especially in the forestry and educational domains. User studies with web developers are planned to gather more evidence about their difficulties employing CRAFTS APIs. Bootstrapping approaches for automating the generation of API configurations are also worth exploring, possibly using a combination of ontology-and data-driven strategies. New functionalities are also envisioned, such as adding support for other popular formats like GraphQL. 21