Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

What

...

is

...

OpenMRS

...

OpenMRS

...

is

...

an

...

electronic

...

medical

...

record

...

platform.

...

Basically

...

we

...

provide

...

an

...

API

...

and

...

data

...

model

...

for

...

storing

...

and

...

analyzing

...

patient-level

...

data,

...

and

...

a

...

reference

...

application

...

that's

...

used

...

in

...

40

...

+

...

mostly-developing

...

countries.

...

The

...

system

...

includes

...

"core"

...

code

...

and

...

pluggable

...

"modules"

...

that

...

allow

...

very

...

powerful

...

extensions

...

of

...

functionality,

...

and

...

UI-level

...

customization.

...

What

...

about

...

Web

...

Services

...

In

...

the

...

past,

...

people

...

have

...

written

...

several

...

web

...

service

...

modules

...

for

...

OpenMRS,

...

but

...

they've

...

never

...

had

...

enough

...

high-level

...

design.

...

Now,

...

for

...

the

...

first

...

time,

...

we're

...

really

...

dedicating

...

our

...

core

...

development

...

team

...

to

...

doing

...

web

...

services

...

right.

...

We

...

need

...

to

...

build

...

a

...

module

...

that

...

exposes

...

our

...

API

...

over

...

web

...

services,

...

in

...

a

...

way

...

that

...

we

...

will

...

support

...

going

...

forwards,

...

and

...

with

...

a

...

design

...

we're

...

proud

...

of.

...

Version

...

1

...

Requirements

...

We

...

polled

...

the

...

broader

...

OpenMRS

...

community,

...

and

...

came

...

up

...

with

...

a

...

list of User Stories to include in Version 1 of the module. Very concisely they are:

  • Get a "patient summary" (i.e.

...

  • a

...

  • big

...

  • chunk

...

  • of

...

  • data

...

  • about

...

  • a

...

  • patient,

...

  • their

...

  • clinical

...

  • encounters,

...

  • etc)

...

  • Create

...

  • a

...

  • new

...

  • encounter

...

  • or

...

  • edit

...

  • an

...

  • existing

...

  • encounter

...

  • for

...

  • a

...

  • patient

...

  • (e.g.

...

  • for

...

  • mobile

...

  • data

...

  • entry)

...

  • Manage

...

  • and

...

  • list

...

  • a

...

  • named

...

  • group

...

  • of

...

  • patients

...

  • (to

...

  • support

...

  • downloading

...

  • summaries

...

  • of

...

  • "My

...

  • patients"

...

  • to

...

  • a

...

  • phone)

...

  • Let

...

  • an

...

  • external

...

  • laboratory

...

  • system

...

  • look

...

  • up

...

  • patients

...

  • and

...

  • metadata

...

  • in

...

  • OpenMRS

...

  • (e.g.

...

  • the

...

  • lab

...

  • system

...

  • fetches

...

  • a

...

  • patient,

...

  • location,

...

  • and

...

  • user

...

  • so

...

  • that

...

  • it

...

  • can

...

  • create

...

  • an

...

  • encounter

...

  • in

...

  • OpenMRS)

...

  • Migrate

...

  • data

...

  • from

...

  • legacy

...

  • systems

...

Design

...

Thoughts

...

and

...

Questions

...

The

...

API

...

we

...

are

...

going

...

to

...

expose

...

in

...

our

...

1.0

...

pass

...

at

...

web

...

services

...

is

...

entirely

...

about

...

doing

...

CRUD

...

on

...

a

...

data

...

store.

...

We're

...

not

...

dealing

...

with

...

any

...

application

...

flow

...

or

...

business

...

logic.

...

As

...

such

...

we

...

will

...

aim

...

for

...

level

...

2

...

of

...

the

...

Richardson

...

Maturity

...

Model (described by Martin Fowler here) and ignore the idea of embedding state transitions in our resources. Is this a mistake?

We will allow Spring to automatically transform our results to json or xml depending on the HTTP request. (This probably prevents us from having a proper DAP or XSD. Is this a mistake?)

We'll be following (mostly) standard practice with HTTP methods for domain object CRUD:

  • Create: POST /ws/rest/patient
  • Search: GET /ws/rest/patient?q=name+or+identifier

...

  • Retrieve:

...

  • GET

...

  • /ws/rest/patient/

...

  • uuid

...

  • Update:

...

  • POST

...

  • /ws/rest/patient/

...

  • uuid with the request content the properties we want to change on the object
    • e.g.

...

    • to

...

    • change

...

    • a

...

    • patient's

...

    • birthdate

...

    • you'd

...

    • POST

...

    • {

...

    • "birthdate":

...

    • "1978-05-24"

...

    • }

...

    • does

...

    • this

...

    • seem

...

    • okay,

...

    • rather

...

    • than

...

    • using

...

    • PUT

...

    • with

...

    • the

...

    • complete

...

    • object?

...

  • Delete:

...

  • DELETE

...

  • /ws/rest/patient/

...

  • uuid

...

    • this

...

    • actually

...

    • means

...

    • "mark

...

    • deleted"

...

    • in

...

    • OpenMRS

...

  • "Delete

...

  • forever":

...

  • DELETE

...

  • /ws/rest/patient/

...

  • uuid

...

  • ?purge=true

...

    • actually

...

    • deletes

...

    • an

...

    • entity

...

    • from

...

    • the

...

    • database

...

    • is

...

    • there

...

    • a

...

    • better

...

    • way

...

    • to

...

    • indicate

...

    • this

...

    • special,

...

    • rarely-used

...

    • method?

...

Our

...

domain

...

objects

...

are

...

often

...

large,

...

and

...

contain

...

lots

...

of

...

rarely-interesting

...

book-keeping

...

information

...

(creator,

...

date

...

created,

...

etc),

...

and

...

we

...

expect

...

many

...

clients

...

to

...

be

...

bandwidth-limited.

...

Therefore

...

we

...

want

...

to

...

allow

...

clients

...

to

...

fetch

...

different

...

representations

...

of

...

a

...

any

...

resource.

...

For

...

example

...

you

...

could

...

get

...

a

...

"default"

...

patient

...

representation

...

(only

...

including

...

the

...

patient's

...

preferred

...

name,

...

not

...

including

...

audit

...

info)

...

or

...

a

...

"full"

...

representation

...

(including

...

all

...

their

...

names,

...

all

...

audit

...

info,

...

etc).

...

Both

...

of

...

these

...

representations

...

would

...

live

...

at

...

the

...

same

...

URI.

...

If

...

the

...

client

...

wants

...

something

...

other

...

than

...

the

...

default

...

representation,

...

they

...

would

...

communicate

...

that

...

by

...

doing

...

a

...

GET

...

with

...

"Accept-Type:

...

full".

...

Is

...

this

...

appropriate?

...

If

...

so,

...

what's

...

the

...

right

...

terminology

...

for

...

this?

...

If

...

not,

...

what

...

alternate

...

approach

...

should

...

we

...

be

...

taking?

...

We

...

also

...

introduce

...

the

...

idea

...

of

...

a

...

"Ref",

...

which

...

is

...

a

...

minimal

...

representation

...

of

...

any

...

object,

...

just

...

containing

...

its

...

uuid,

...

a

...

displayable

...

string,

...

and

...

a

...

URI

...

link

...

to

...

the

...

full

...

resource.

...

So

...

for

...

example

...

if

...

I

...

fetch

...

the

...

default

...

representation

...

of

...

a

...

patient,

...

I

...

might

...

get

...

this:

...

}
Code Block
{
  "personAddress" : {
    "uuid" : "3350d0b5-821c-4e5e-ad1d-a9bce331e118",
    "display" : "1050 Wishard Blvd., RG5, Indianapolis, IN",
    "uri" : "http://.../ws/rest/personaddress/3350d0b5-821c-4e5e-ad1d-a9bce331e118"
  },
  /* more stuff */
}
{code}

Whereas

...

if

...

I

...

fetch

...

the

...

full

...

representation

...

of

...

a

...

patient

...

I

...

might

...

get:

...

}
Code Block
{
  "personAddress" : {
    "uuid" : "3350d0b5-821c-4e5e-ad1d-a9bce331e118",
    "address1" : "1050 Wishard Blvd.",
    "address2" : "RG5",
    "cityVillage" : "Indianapolis",
    "stateProvince" : "IN",
    "uri" : "http://.../ws/rest/personaddress/3350d0b5-821c-4e5e-ad1d-a9bce331e118"
  },
  /* more stuff */
}
{code}

A

...

more

...

relevant

...

example

...

of

...

this

...

is

...

that

...

an

...

encounter

...

might

...

contain

...

100

...

observations.

...

The

...

default

...

encounter

...

representation

...

would

...

just

...

include

...

a

...

displayable

...

"weight

...

=

...

70",

...

whereas

...

the

...

full

...

encounter

...

representation

...

would

...

include

...

full

...

details

...

about

...

the

...

"weight"

...

question

...

(e.g.

...

that

...

it's

...

unit

...

is

...

"kg",

...

its

...

range

...

is

...

0-250,

...

etc).

...

Is

...

this

...

okay,

...

or

...

is

...

this

...

some

...

sort

...

of

...

anti-pattern

...

that's

...

going

...

to

...

get

...

us

...

into

...

trouble?

...

We

...

also

...

have

...

the

...

idea

...

of

...

"sub-resources".

...

Take

...

the

...

example

...

of

...

a

...

"Program"

...

(e.g.

...

"Tuberculosis

...

Treatment

...

Program")

...

and

...

a

...

"Program

...

Enrollment"

...

(i.e.

...

a

...

patient

...

may

...

be

...

enrolled

...

in

...

a

...

program

...

from

...

date

...

X

...

to

...

date

...

Y).

...

 Our plan

...

is

...

that:

...

  • A

...

  • patient's

...

  • program

...

  • enrollment

...

  • has

...

  • a

...

  • top-level

...

  • URI

...

  • /ws/rest/enrollment/

...

  • uuid

...

  •  (i.e.

...

  • it's

...

  • not

...

  • included

...

  • within

...

  • the

...

  • patient)

...

  • To

...

  • see

...

  • what

...

  • programs

...

  • a

...

  • patient

...

  • is

...

  • enrolled

...

  • in:

...

  • GET

...

  • /ws/rest/patient/

...

  • patient-uuid

...

  • /enrollments

...

  • To

...

  • see

...

  • what

...

  • patients

...

  • are

...

  • enrolled

...

  • in

...

  • a

...

  • program:

...

  • GET

...

  • /ws/rest/program/

...

  • program-uuid

...

  • /patients

...

  • To

...

  • enroll

...

  • a

...

  • patient

...

  • in

...

  • a

...

  • program

...

  • you

...

  • can

...

  • do either of:
    • POST /ws/rest/patient/

...

    • patient-uuid

...

    • /enrollments

...

    •  //

...

    • may

...

    • omit

...

    • the

...

    • patient

...

    • from

...

    • the

...

    • request

...

    • body

...

    • POST

...

    • /ws/rest/program/

...

    • program-uuid

...

    • /patients

...

    •  //

...

    • may

...

    • omit

...

    • the

...

    • program

...

    • from

...

    • the

...

    • request

...

    • body

...

    • POST

...

    • /ws/rest/enrollment

...

    •  //

...

    • must

...

    • specify

...

    • both

...

    • patient

...

    • and

...

    • program

...

    • in

...

    • the

...

    • request

...

    • body

...

Does

...

this

...

sound

...

right?

...

Some Java Code

We've

...

tried

...

to

...

put

...

together

...

a

...

framework

...

that

...

will

...

make

...

it

...

very

...

quick

...

to

...

expose

...

each

...

of

...

our

...

existing

...

domain

...

objects

...

as

...

resources

...

in

...

a

...

standard

...

way,

...

while

...

still

...

giving

...

us

...

flexibility

...

to

...

step

...

out

...

of

...

that

...

pattern

...

if

...

need

...

be.

...

To

...

create

...

and

...

expose

...

a

...

resource

...

you

...

would

...

have

...

to

...

write

...

two

...

classes:

...

...

...

  • implementations

...

  • of

...

  • getByUniqueId,

...

  • save,

...

  • etc,

...

  • and

...

  • descriptions

...

  • of

...

  • the

...

  • available

...

  • representations)

...

  • 

...

  • PatientController (contains short methods to connect Spring MVC's request handling to PatientResource)

We've tried to standardize the way we do CRUD via interfaces (Creatable, Retrievable, Updatable, Deletable, Purgeable), and via a base class that helps reflect these interfaces onto our pre-web-service domain objects: DelegatingCrudResource.