Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended yaml API specification #357

Merged
merged 2 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ A grlc API specification file is a YAML file which includes the necessary inform
- `description`: API description
- `contact`: Contact details of the API owner. This should include the `name` and `url` properties.
- `licence`: A URL pointing to the licence file for the API.
- `queries`: A list of URLs of SPARQL queries (with header decorators).
- `queries`: A list of URLs of SPARQL queries (with header decorators). Alternatively a query can be defined as a dictionary with a `name` and a `url`.

For example:
```YAML
Expand All @@ -97,6 +97,8 @@ queries:
- https://www.mywebsite.org/query1.rq
- https://www.mywebsite.org/query2.rq
- https://www.otherwebsite.org/query3.rq
- name: QueryFour
url: https://www.mywebsite.org/query4.rq
```

### grlc generated API
Expand Down
54 changes: 39 additions & 15 deletions src/fileLoaders.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import grlc.static as static
from grlc.queryTypes import qType
from grlc.queryTypes import qType, guessQueryType
import grlc.glogging as glogging

import json
Expand All @@ -23,15 +23,14 @@ def getTextForName(self, query_name):
for `query_name='query1'` would return the content of file `query1.rq`
from the loader's source (assuming such file exists)."""
# The URIs of all candidates
rq_name = query_name + '.rq'
sparql_name = query_name + '.sparql'
tpf_name = query_name + '.tpf'
json_name = query_name + '.json'
candidateNames = [
query_name + '.rq',
query_name + '.sparql',
query_name + '.tpf',
query_name + '.json'
]
candidates = [
(rq_name, qType['SPARQL']),
(sparql_name, qType['SPARQL']),
(tpf_name, qType['TPF']),
(json_name, qType['JSON'])
(name, guessQueryType(name)) for name in candidateNames
]

for queryFullName, queryType in candidates:
Expand Down Expand Up @@ -257,7 +256,6 @@ def getRepoDescription(self):
return self.api_description



class URLLoader(BaseLoader):
"""URL specification loader. Retrieves information to construct a grlc
specification from a specification YAML file located on a remote server."""
Expand All @@ -273,18 +271,33 @@ def __init__(self, spec_url):
self.spec = yaml.load(resp.text)
self.spec['url'] = spec_url
self.spec['files'] = {}
for queryUrl in self.spec['queries']:
queryNameExt = path.basename(queryUrl)
queryName = path.splitext(queryNameExt)[0] # Remove extention

for query in self.spec['queries']:
queryName, queryUrl = self.extractQueryInfo(query)

item = {
'name': queryName,
'download_url': queryUrl
}
self.spec['files'][queryNameExt] = item
self.spec['files'][queryName] = item
del self.spec['queries']
else:
raise Exception(resp.text)

def extractQueryInfo(self, query):
"""Extract query name and URL from specification. These could
either be explicitly declared (values in a dict) or need to be
infered from the URL (which itself could be explicilty declared or
be the only element of query."""
queryUrl = query['url'] if type(query) is dict else query

if type(query) is dict and 'name' in query:
queryName = query['name']
else:
queryNameExt = path.basename(queryUrl)
queryName = path.splitext(queryNameExt)[0] # Remove extention
return queryName, queryUrl

def fetchFiles(self):
"""Returns a list of file items contained on specification."""
files = [
Expand All @@ -300,7 +313,18 @@ def getTextFor(self, fileItem):
"""Returns the contents of the given file item on the specification."""
# TODO: tiene sentido esto? O es un hack horrible ?
nameExt = path.basename(fileItem['download_url'])
return self._getText(nameExt)
return self._getText(fileItem['name'])

def getTextForName(self, query_name):
"""Return the query text and query type for the given query name.
Specific implementation for URLLoader."""
try:
queryText = self._getText(query_name)
queryType = guessQueryType(self.spec['files'][query_name]['download_url'])
return queryText, queryType
except Exception as e:
# No query found...
return '', None

def _getText(self, itemName):
"""Return the content of the specified item in the specification."""
Expand Down
13 changes: 13 additions & 0 deletions src/queryTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,16 @@
'TPF': 'tpf',
'JSON': 'json'
}

def guessQueryType(queryUrl):
queryUrl = queryUrl.lower()
if queryUrl.endswith('.rq'):
return qType['SPARQL']
elif queryUrl.endswith('.sparql'):
return qType['SPARQL']
elif queryUrl.endswith('.tpf'):
return qType['TPF']
elif queryUrl.endswith('.json'):
return qType['JSON']
else:
raise Exception('Unknown query type: ' + queryUrl)