fhir / fhir.js Goto Github PK
View Code? Open in Web Editor NEWJavaScript client for FHIR
JavaScript client for FHIR
When attempting to run the "npm run-script build" command I get an error as seen in the log (also attached):
verbose stack Error: [email protected] build: rm -rf dist && 'npm bin'/webpack --progress --colors && coffee --output lib --compile src
To confirm that I did indeed have the latest and greatest version of NodeJS and NPM I re-installed both:
node Version - v5.7.0
npm Version - v3.7.5
and ran the npm build script again with the same result.
Any suggestions?
Thanks
I see that there are some provisions for a cache mechanism in fhir.js, but does not seem like it is fully developed yet. For example, a cache
object is instantiated here, but never gets used in the code. Furthermore, the only use of cache in the code appears to occur in the resolve method iff an externally-originating cache object is passed with the call. I can see that there is some notion of an externalized cache mechanism which could support some use cases, but at the moment it leaves the population and management of this cache object entirely to the app using the client. Wouldn't it be better if the client had its own cache object available in all modules which it could manage (i.e. populate as data arrives from FHIR) and take advantage of? This mechanism could be triggered on and off via a configuration option.
Related to this, the synchronous resolve
method is no longer exposed by the client. To get around this (since I don't want to call resolve
for data which I already have retrieved and also have to manage it as an asynchronous method), I added my own cache resolver in the code (https://github.com/smart-on-fhir/bp-centiles-app/blob/f55cc937f7a5fd1360eff8e17eef484313dffd95/js/load-fhir-data.js#L34). However, my sense is that this is a fairly common use case and it would be handy if the client supported it.
should we name adapters according to technology name ?
I would like to do Operation-patient-everything kind of query using fhir.js client. Please refer to https://www.hl7.org/fhir/operation-patient-everything.html. Does the search API allow me do this kind of query? If yes, how do I populate search API queryParam in order to trigger this operation on a compliant FHIR server?
Coffesript hides some bad parts of javascript and allows write less boilerplate,
but has some complication while development.
Now it's easy to build fhir.js by
`bin npm`/grunt
Karma automaticaly complile coffee and inject into tests.
node_modules/karma/bin/karma start --single-run
expect(subject($include: {$type: 'Encounter', subject: true, object: true}))
.toBe('_include=Encounter.subject&_include=Encounter.object')
expect(subject($include: '*'))
.toBe('_include=*')
expect(subject($include: {$type: 'Encounter', subject: {$type: 'Patient', $all: true}, object: true}))
.toBe('_include=Encounter.subject&_include=Patient.*&_include=Encounter.object')
expect(subject($include: {$type: 'Encounter', subject: {$type: 'Patient', managingOrganization: true}, object: true}))
.toBe('_include=Encounter.subject&_include=Patient.managingOrganization&_include=Encounter.object')
Includes
in FHIR specification require knowledge of element/attribute type - possibly use magic $type
If do this right, the library (+/- adapters) should work in browser as well as Node, yes?
e.g.
Line 23 in 77f0008
I am trying to express the following FHIR query:
/Patient?_sort:asc=given&_sort:asc=family&_count=25
in the fhir.js search syntax, but am having trouble. At first sight, it looks like the following would produce the desired result:
{type: 'Patient', query: {'_sort:asc':['given', 'family'], _count:25}}
but that does not work. What am I missing here?
#63 adds behavior to automatically send cookies when requesting content from third party domains. I think this is potentially dangerous behavior and we should think through security more systematically. Why? Because in many cases (e.g. when using OAuth) a client doesn't want to send cookies, and sending them would lead to confusing or undefined behavior (and that's bad in the security domain).
We already have security middlewares for OAuth (for sure) and http basic (I think).
@arcticShadow @niquola We should add one for cookies, too, so unless that's enabled, no cookies are sent to any domain. Enabling cookies should add a property to the http options (e.g. "withCredentials: true", as in https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials).
To support this, adapters will need to read that field and set the appropriate value on all requests they issue.
Also let me say @arcticShadow: protecting a FHIR API with cookies and CORS in general strikes me as a dangerous proposition, and unless you get all the details precisely correct (https only, no JS, csrf tokens, zero xss bugs...) it's very easy to find yourself in a situation where you hand over full API access to an attacker.
The question is:
what should return create
and update
- 'Content-Location' or resource?
Jasmine tests are too unpredictable :(
Let's switch to mocha!
I was testing the jQuery version of the client and had issues with the nextPage
and resolve
methods, which were resulting in incorrect HTTP requests. The underlying reason appeared to be that a loaded data
argument gets passed all the way through to the http
adapter which then injects it into the GET request. This behavior probably makes sense for the search method, but not for nextPage
and resolve
where we have a specific REST call URL either provided by the server or computed against a resource. It appears that clearing the data
argument in these middleware call instances resolves the issue, but this feels more like a hack than a "proper" fix for the underlying issue (see smart-on-fhir@936bd70 and smart-on-fhir@30a1670). Do you have any thoughts on this?
Resource contains resourceType attribute, should we pass it in create
function explicitly or retrieve from resourceType?
fhir.create('Patinet', json, cb)
or
fhir.create(json, cb)
Second question is about tags:
Should they be second optional? parameter?
create(resourceJson, tags, cb)
What is format of tags in json?
{ term: "...", schema: "...", label: "..."}
fhir.js tests should not depend on external FHIR servers, just start simple http server mocking fhir.js requests by predefined responces.
Proposal to use mongo-like syntax - http://docs.mongodb.org/manual/tutorial/query-documents/
{name: 'maud'}
//=> name=maud
{name: {$exact: 'maud'}}
//=> name:exact=maud
{name: {$or: ['maud','dave']}}
//=> name=maud,dave
{name: {$and: ['maud',{$exact: 'dave'}]}}
//=> name=maud&name:exact=Dave
{birthDate: {$gt: '1970', $lte: '1980'}}
//=> birthDate=>1970&birthDate=<=1980
{subject: {$type: 'Patient', name: 'maud', birthDate: {$gt: '1970'}}}
//=> subject:Patient.name=maud&subject:Patient.birthDate=>1970
{'subject.name': {$exact: 'maud'}}
//=> subject.name:exact=maud
Data-drive DSLs are interoperable, composable & re-interpretable.
Havig a query as self-contained is good thing.
For example, adding an obvious error to a source file (say, search.coffee
line 15) yields unhelpful error messages when tests fail, like:
TypeError: 'null' is not a function (evaluating 'a()')
at ~/fhir.js/test/fhirSpec.coffee:842:0
Need source maps back to the original files to interpret these messages.
should include data and headers
it looks like there is no way to get custom headers in phantomjs launcher
in chrome launcher works great
any ideas ?
"Access-Control-Expose-Headers" "Location, Content-Location, Category, Content-Type"
Now possibility to break one adapter while fixing another is very high!
We should design reusable integration test, which could be applied to all adapters and guarantying they are complaint to expected interface.
Should be changed in search.coffee
l.rel -> l.relation
l.href -> l.url
Current README suggests something promise-like, i.e.
fhir.search('Patient', queryObject)
.then(function(bundle){...})
Should we rely on (or provide a base implementation of) promises, and then wrap those as (jquery/ng/whatever) framework-specific promises in adapters?
Or should we just provide a totally generic callback API in the base package, like
fhir.search('Patient', queryObject, onSuccess, onError);
I'm okay either way, but want to raise the question.
The native adapter currently only send cookies to same-origin fhir servers. Patch attached that fixes this.
"nextPage" and "prevPage" need to be added to list of methods exposed in src/adapters/node.coffee
As the Modern web world moves forward, Things like Promises, and http retrieval libraries are becoming defacto standard across browsers. (And where they are not, there are some really useful polyfill libraries)
Using a native implementation (Or a polyfill) has advantages in that you do not need an entire framework (jQuery, angular, YUI etc) in order to be able to use this library.
I currently have a patched verison that uses Native Promise and Fetch API's that I would like to contribute back.
A sample is below - I will clean it up for a Proper PR. The sample is for illustrative purposes only. (Also, sample is written in ES2015 as is the rest of my project.
import mkFhir from 'fhir.js/src/fhir';
import _ from 'lodash';
// Build a backwards compatiable defer object
const defer = () => {
const def = {};
def.promise = new Promise((resolve, reject) => {
def.resolve = resolve;
def.reject = reject;
});
return def;
};
const adapter = {
http: (args) => {
const url = args.url;
const debug = args.debug;
const fetchOptions = _.omit(args, ['debug', 'url']);
fetchOptions.credentials = 'same-origin';
if (debug) {
console.log('DEBUG[native]: (request)', args); // eslint-disable-line
}
const retPromise = defer();
const returnableObject = {};
fetch(url, fetchOptions).then((response) => {
_.merge(returnableObject, {
status: response.status,
headers: response.headers,
config: args,
});
return response;
}).then((response) => {
if (!_.inRange(response.status, 200, 399)) {
console.log('DEBUG[native]: (fail response)', returnableObject); // eslint-disable-line
retPromise.reject(returnableObject);
}
return response;
}).then((response) => {
return response.json();
}).then((json) => {
_.merge(returnableObject, {
data: json,
});
console.log('DEBUG[native]: (success response)', returnableObject); // eslint-disable-line
retPromise.resolve(returnableObject);
});
return retPromise.promise;
},
};
We could use closure instead of classes
to initialize instances of fhir:
function mkFhir(config, adapter){
return {
search: mkSearch(config, adapter),
auth: mkAuth(config, adapter),
....
}
)
At least we could skip new
keyword :)
This commit updates the pagination code with DSTU2:
smart-on-fhir@7407ed4
I see that there is a dstu2
branch in the repo already, but seems out of date with the latest code. Could we get the dstu2
branch up to speed so that we can merge this in?
package.json mentions MIT license, can explicit LICENSE(.md) file be added?
We say:
success - success callback, which should be called with (data, status, headersFn, config)
data - parsed body of responce
status - responce HTTP status.
headerFn - function to get header, i.e. headerFn('Content')
config - initial requestObj passed to http
... but the caller's success callback only ever gets one arg. Should we expose all 4 to the caller?
Overall, though, I see this as an area where a client library can and should step up to the plate: in ~30 lines of JavaScript code, for example, I can (generically) parse a FHIR JSON bundle into an in-memory graph where references are replaced with direct links across data structures. And that approach is robust to recursive relations, repeated data, etc.
You ask that as though I've actually written it ;-)
But sure, yes, it can be made reusable. The operation would take:Input: FHIR atom bundle, and a "focus" resource (or resources)
Output: an in-memory representation of the "focus" resources where references are replaced with object linksAlgorithm:
- JSON parse every resource in the bundle, adding each to a "cache" object keyed by id
- Recurse over the structure of the "focus" resource to transform each reference using...
- Transformation: resourceElement[property] = cache[resourceElement[key].reference]
by @jmandel from fhir mail list
Im interested in contributing a YUI adapter for fhir.js. Would you be interested in accepting a pull request for this?
Hi,
I'm seeing the following errors when integrating fhir.js into a React app and running webpack:
WARNING in .//fhir.js//request/lib/optional.js
Critical dependencies:
9:13-32 the request of a dependency is an expression
@ .//fhir.js//request/lib/optional.js 9:13-32
ERROR in .//fhir.js//request/request.js
Module not found: Error: Cannot resolve module 'net' in /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/request
@ .//fhir.js//request/request.js 33:10-24
ERROR in .//tunnel-agent/index.js/tunnel-agent/index.js 3:10-24
Module not found: Error: Cannot resolve module 'net' in /Users/andrewhall/Documents/fihr-store/node_modules/tunnel-agent
@ ./
ERROR in .//tunnel-agent/index.js/tunnel-agent/index.js 4:10-24
Module not found: Error: Cannot resolve module 'tls' in /Users/andrewhall/Documents/fihr-store/node_modules/tunnel-agent
@ ./
ERROR in .//fhir.js//forever-agent/index.js
Module not found: Error: Cannot resolve module 'net' in /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/forever-agent
@ .//fhir.js//forever-agent/index.js 6:10-24
ERROR in .//fhir.js//forever-agent/index.js
Module not found: Error: Cannot resolve module 'tls' in /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/forever-agent
@ .//fhir.js//forever-agent/index.js 7:10-24
ERROR in .//fhir.js//mime-types/lib/custom.json
Module parse failed: /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/mime-types/lib/custom.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "text/jade": [
| "jade"
| ],
@ .//fhir.js//mime-types/lib/index.js 13:10-34
ERROR in .//fhir.js//mime-types/lib/node.json
Module parse failed: /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/mime-types/lib/node.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "text/vtt": [
| "vtt"
| ],
@ .//fhir.js//mime-types/lib/index.js 12:8-30
ERROR in .//fhir.js//mime-types/lib/mime.json
Module parse failed: /Users/andrewhall/Documents/fihr-store/node_modules/fhir.js/node_modules/mime-types/lib/mime.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "application/1d-interleaved-parityfec": [],
| "application/3gpp-ims+xml": [],
| "application/activemessage": [],
@ .//fhir.js//mime-types/lib/index.js 11:8-30
Any ideas?
Optionally, the history
calls should support a query param to express _count
and _since
.
In our wrapper library for fhir.js, I implemented fetchAll
and drain
methods to facilitate retrieval of paginated bundles by apps (https://github.com/smart-on-fhir/client-js/blob/2045a37dfdf930919f6ef87c9eede62224a574cf/src/client/client.js#L137). This works well, but I am thinking that these methods probably belong inside the fhir.js
library. The problem is that they don't exactly fit in the current middle-wares model which seems geared towards supporting a single REST call to the API server. How can we get these methods ported gracefully into the fhir.js code base?
Hello, I've been working with your library in nodejs.
I've successfully got read and search working, however create and update consistently give the error "id = headers('Content-Location') ---- typeError: undefined is not a function", (found in resource.js) I have attempted to change id = headers && headers('Content-Location') || ?? like the read function, which produced a 'Content-Type' hasn't been declared error for update. I put the content-type in headers as well which led to a can not parse JSON error. Finally I retrieved the patient object which would update in my console but not on the server. (I'm using UHN's). I would greatly appreciate some assistance!
This is my entry:
var entry =
{
category: [{term: 'TAG term', schema: 'TAG schema', label: 'TAG label'}],
content:
{
resourceType: "Patient",
name:
[
{
family: ["Bob"],
given: ["Smith"]
}
],
birthDate: '1990-06-20'
}
};
this is my create statement:
var test = client.create(entry, function(err, entry)
{
console.log(entry.id);
console.log(err);
});
this is how I instantiate the client:
var client = new mkFhir({
baseUrl: 'http://fhirtest.uhn.ca/baseDstu1'
});
For the nodejs build at least, we should have a "prepublish" script in package.json
and then publish to .js files that way to npm.
We should create strategy to handle resource ids & uris in API uniformly.
Looks like we do not need ids, only urls.
Proposal:
entry.id => current resource url
links[rel=self] => history resource url
Here we see weakness of FHIR: it is not hypermedia REST :(
If it would be hypermedia driven, we only have to hard code one url => entry point (baseURL),
all other resources and interaction's urls could be then read from hypertext controls like links & forms (i.e. media type specification)
Preferred way is not code generation, but generic functions:
fhir.validate(resource, profile) //=> list of errors
fhir.convert(json, profile) //=> xml
If we would pass to all api functions only one hash-map (object), it would be easy to read & write (to many positional params is not good), add new params, support default params
update(entry, cb, err)
=> update({entry: x, success: cb, error: err})
Client should have functions to help with pagination. For example:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.