← Back to team overview

dhis2-devs team mailing list archive

Re: External api for posting data values

 

On 15 February 2011 15:27, Murod Latifov <mlatifov@xxxxxxxxx> wrote:
> Hi Bob,
>
> Where are other possible dataelements and their categorycombos here? I don't
> see this xml being valid considering how different dataSets will look like.

Well trying with one datavalue was easier to type :-)  Whether a
datavalueset must necessarily be "complete" is a design issue.  I
guess Jo could work it either way - but its nice not have to send lots
of empty elements if you've only got one value to send.

>
> At least it should look something like this:
>
> <dataValueSet xmlns="http://dhis2.org/schema/dataValueSet/0.1";
>    dataSet="EEEE2762-6432-4C9A-
>>
>> A739-8E7F1D74F60F"
>>    period="2011"
>>    orgUnit="59AC3C28-DDCE-435C-8695-8E457127DADC"
>>    storedBy="Bob">
>>  <dataValue dataElements>
>
>  <dataValue>34
>  <dataElements>
>  <dataValue>
> <dataElement uuid="uuid40">
> <categoryCombo uuid="uuid40">
> <value>34<value/>
> <categoryCombo/>
> <dataElement/>
> <dataValue/>
>  <dataValue>
> <dataElement uuid="uuid40">
> <categoryCombo uuid="uuid40">
> <value>34<value/>
> <categoryCombo/>
> <dataElement/>
> <dataValue/>
> <dataElements>
>  </dataValue>
> <...as many as they are>
>>
>> </dataValueSet>
>
> etc. xml
>
> cheers,
> murod
>
> On Tue, Feb 15, 2011 at 2:10 PM, Bob Jolliffe <bobjolliffe@xxxxxxxxx> wrote:
>>
>> Works very nicely.  Just posted a file (dvset.xml):
>>
>> <dataValueSet xmlns="http://dhis2.org/schema/dataValueSet/0.1";
>>    dataSet="EEEE2762-6432-4C9A-A739-8E7F1D74F60F"
>>    period="2011"
>>    orgUnit="59AC3C28-DDCE-435C-8695-8E457127DADC"
>>    storedBy="Bob">
>>  <dataValue dataElement="B01190B8-808C-42C4-AA6F-3F9CF51DC44F"
>> >34</dataValue>
>> </dataValueSet>
>>
>> using
>>
>> curl http://admin:district@xxxxxxxxxxx/dev/api/rpc/dataValueSets -H
>> "Content-Type: application/xml" -d @dvset.xml
>>
>> Simple validation seems to work ok.  I get an "Aw, Snap! ..." when
>> posting twice with the same period but that is probably something you
>> are not catching yet.
>>
>> On 15 February 2011 10:14, Jo Størset <storset@xxxxxxxxx> wrote:
>> > Hi,
>> >
>> > just commited a spike for simple(?) external posting of data values.
>> > This is a tricky area to design, so I'm hoping this can generate some
>> > discussions around it.
>> >
>> > The immediate use case for this is an external server doing doing the
>> > data collection (mobile based), and then needing an easy way to post
>> > dataValueSets, with what I think is more detailed automated validation and
>> > feedback than the imp/exp would allow for..
>> >
>> > You should be able to try it out by going to [1] (or correspondingly to
>> > your local instance) and follow the instructions on screen.
>> >
>> > I've tried to promote dataSet and the corresponding dataValueSet as top
>> > level concepts, as I think this makes more sense than having isolated data
>> > values..
>> >
>> > Also, I've created representation for dataValueSet, that is sort of
>> > dxf-like, but doesn't really make for the batch-oriented import/export
>> > dxf/sdmx is intended for.
>> > It is possible to tweak the format to be more batch-friendly, but I'm
>> > not convinced the use cases for this vs. batch are really similar enough
>> > that it makes sense at the cost of simplicity.
>>
>> I don't agree with this.  If we have to create two separate xml
>> dialects to handle what you term batch and non-batch (?) then we
>> really have things wrong.  So we do need to harmonize this.  Having
>> said that I am very happy to leave dxf v1 where it stands and look to
>> v2 which should be well enough designed to handle a variety of
>> scenarios..
>>
>> Your use of DataValueSet here is very welcome - as you know I have
>> been advocating this for a while.  Would be nice also to persist it to
>> provide audit (and simplify dtavalue store) but that is maybe too much
>> for now.
>>
>> We would need to think about uuids - particularly with larger
>> payloads, but otherwise what you are doing here seems to be the
>> correct way to go.  perhaps with the advent of stable identifiers, we
>> might have an optional uuid vs id tag to identify the items.
>>
>> Looking good ....
>>
>> Cheers
>> Bob
>>
>> > One of the things this solution allows for, btw, is use of json instead
>> > of xml.
>> >
>> > I think we do want an api more in this direction than the current
>> > import/export stuff will allow for, but I'm not in any way sure this is the
>> > right way to start off. In other words, maybe going with a layer above a
>> > reworked version of the xsl/xml based imp/exp framework would be better
>> > overall?
>> >
>> > Anyway, have a quick look and feed back :)
>> > Jo
>> >
>> > [1] http://dhis.uio.no/dev/api/rpc
>> >
>> >
>> > Den 15. feb. 2011 kl. 12.29 skrev noreply@xxxxxxxxxxxxx:
>> >
>> >> ------------------------------------------------------------
>> >> revno: 2851
>> >> committer: Jo Størset <storset@xxxxxxxxx>
>> >> branch nick: dhis2
>> >> timestamp: Tue 2011-02-15 12:23:26 +0530
>> >> message:
>> >>  Added spike for storing dataValueSets through a simple http post (see
>> >> <dhis-root-url>/api/rpc)
>> >> added:
>> >>
>> >>  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/mapping/IllegalArgumentExceptionMapper.java
>> >>  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc/
>> >>
>> >>  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc/RPCResource.java
>> >> modified:
>> >>
>> >>  dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml
>> >>
>> >>
>> >> --
>> >> lp:dhis2
>> >> https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
>> >>
>> >> Your team DHIS 2 developers is subscribed to branch lp:dhis2.
>> >> To unsubscribe from this branch go to
>> >> https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
>> >> === added file
>> >> 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/mapping/IllegalArgumentExceptionMapper.java'
>> >> ---
>> >> dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/mapping/IllegalArgumentExceptionMapper.java
>> >>      1970-01-01 00:00:00 +0000
>> >> +++
>> >> dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/mapping/IllegalArgumentExceptionMapper.java
>> >>      2011-02-15 06:53:26 +0000
>> >> @@ -0,0 +1,23 @@
>> >> +package org.hisp.dhis.web.api.mapping;
>> >> +
>> >> +import javax.ws.rs.core.MediaType;
>> >> +import javax.ws.rs.core.Response;
>> >> +import javax.ws.rs.core.Response.Status;
>> >> +import javax.ws.rs.ext.ExceptionMapper;
>> >> +import javax.ws.rs.ext.Provider;
>> >> +
>> >> +import com.sun.jersey.spi.resource.Singleton;
>> >> +
>> >> +@Provider
>> >> +@Singleton
>> >> +public class IllegalArgumentExceptionMapper
>> >> +    implements ExceptionMapper<IllegalArgumentException>
>> >> +{
>> >> +
>> >> +    @Override
>> >> +    public Response toResponse( IllegalArgumentException e )
>> >> +    {
>> >> +        return Response.status( Status.CONFLICT ).entity( "Problem
>> >> with input: " + e.getMessage() ).type( MediaType.TEXT_PLAIN ).build();
>> >> +    }
>> >> +
>> >> +}
>> >>
>> >> === added directory
>> >> 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc'
>> >> === added file
>> >> 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc/RPCResource.java'
>> >> ---
>> >> dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc/RPCResource.java
>> >>     1970-01-01 00:00:00 +0000
>> >> +++
>> >> dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/web/api/rpc/RPCResource.java
>> >>     2011-02-15 06:53:26 +0000
>> >> @@ -0,0 +1,189 @@
>> >> +package org.hisp.dhis.web.api.rpc;
>> >> +
>> >> +import java.net.URI;
>> >> +import java.util.List;
>> >> +import java.util.Set;
>> >> +
>> >> +import javax.ws.rs.Consumes;
>> >> +import javax.ws.rs.GET;
>> >> +import javax.ws.rs.POST;
>> >> +import javax.ws.rs.Path;
>> >> +import javax.ws.rs.PathParam;
>> >> +import javax.ws.rs.Produces;
>> >> +import javax.ws.rs.core.Context;
>> >> +import javax.ws.rs.core.MediaType;
>> >> +import javax.ws.rs.core.Response;
>> >> +import javax.ws.rs.core.Response.Status;
>> >> +import javax.ws.rs.core.UriInfo;
>> >> +
>> >> +import org.hisp.dhis.dataelement.DataElement;
>> >> +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
>> >> +import org.hisp.dhis.dataset.DataSet;
>> >> +import org.hisp.dhis.dataset.DataSetService;
>> >> +import org.hisp.dhis.datavalue.DataValue;
>> >> +import org.hisp.dhis.datavalue.DataValueService;
>> >> +import org.hisp.dhis.importexport.datavalueset.DataValueSet;
>> >> +import org.hisp.dhis.importexport.datavalueset.DataValueSetMapper;
>> >> +import org.hisp.dhis.organisationunit.OrganisationUnit;
>> >> +import org.springframework.beans.factory.annotation.Required;
>> >> +
>> >> +import com.ibatis.common.logging.Log;
>> >> +import com.ibatis.common.logging.LogFactory;
>> >> +
>> >> +@Path( "/rpc" )
>> >> +public class RPCResource
>> >> +{
>> >> +    private static Log log = LogFactory.getLog( RPCResource.class );
>> >> +
>> >> +    private DataValueSetMapper dataValueSetMapper;
>> >> +
>> >> +    private DataValueService dataValueService;
>> >> +
>> >> +    private DataSetService dataSetService;
>> >> +
>> >> +    @Context
>> >> +    UriInfo uriInfo;
>> >> +
>> >> +    @POST
>> >> +    @Path( "dataValueSets" )
>> >> +    @Consumes( MediaType.APPLICATION_XML )
>> >> +    public void storeDataValueSet( DataValueSet dataValueSet )
>> >> +    {
>> >> +        List<DataValue> dataValues = dataValueSetMapper.getDataValues(
>> >> dataValueSet );
>> >> +
>> >> +        for ( DataValue dataValue : dataValues )
>> >> +        {
>> >> +            dataValueService.addDataValue( dataValue );
>> >> +        }
>> >> +    }
>> >> +
>> >> +    @GET
>> >> +    @Produces( MediaType.TEXT_HTML )
>> >> +    @Path( "dataSets" )
>> >> +    public String getDataValueSets()
>> >> +    {
>> >> +        return getDataValueSet();
>> >> +    }
>> >> +
>> >> +    @GET
>> >> +    @Produces( MediaType.TEXT_HTML )
>> >> +    public String getDataValueSet()
>> >> +    {
>> >> +        StringBuilder t = new StringBuilder();
>> >> +        t.append( head( "Data sets available for reporting" ) );
>> >> +
>> >> +        t.append( "<h2>Data sets available for reporting</h2>\n<ul>\n"
>> >> );
>> >> +        for ( DataSet dataSet : dataSetService.getAllDataSets() )
>> >> +        {
>> >> +            URI uri = uriInfo.getBaseUriBuilder().path(
>> >> "rpc/dataSets/{uuid}" ).build( dataSet.getUuid() );
>> >> +            t.append( "<li>" ).append( "<a href=\"" ).append( uri
>> >> ).append( "\">" ).append( dataSet.getName() )
>> >> +                .append( "</a></li>\n" );
>> >> +        }
>> >> +        xmlTemplate( t );
>> >> +        t.append( tail() );
>> >> +
>> >> +        return t.toString();
>> >> +    }
>> >> +
>> >> +    @GET
>> >> +    @Path( "dataSets/{uuid}" )
>> >> +    @Produces( MediaType.TEXT_HTML )
>> >> +    public String getDataSet( @PathParam( "uuid" ) String uuid )
>> >> +    {
>> >> +
>> >> +        DataSet dataSet = dataSetService.getDataSet( uuid );
>> >> +
>> >> +        if ( dataSet == null )
>> >> +        {
>> >> +            throw new IllegalArgumentException( "No dataset with uuid
>> >> " + uuid );
>> >> +        }
>> >> +
>> >> +        StringBuilder t = new StringBuilder();
>> >> +
>> >> +        t.append( head( "Data set " + dataSet.getName() ) );
>> >> +        t.append( "<p>Uuid: " ).append( dataSet.getUuid() ).append(
>> >> "<br>\n" );
>> >> +        t.append( "Period type: " ).append(
>> >> dataSet.getPeriodType().getName() ).append( " - " )
>> >> +            .append( dataSet.getPeriodType().getIsoFormat() );
>> >> +        t.append( "</p>\n" );
>> >> +
>> >> +        t.append( "<h2>Org units reporting data set</h2>\n<ul>" );
>> >> +        for ( OrganisationUnit unit : dataSet.getOrganisationUnis() )
>> >> +        {
>> >> +            t.append( "<li><b>" ).append( unit.getName() ).append(
>> >> "</b> - " ).append( unit.getUuid() )
>> >> +                .append( "</li>" );
>> >> +        }
>> >> +        t.append( "</ul>\n" );
>> >> +
>> >> +        t.append( "<h2>Data elements in data set</h2>\n<ul>" );
>> >> +        for ( DataElement element : dataSet.getDataElements() )
>> >> +        {
>> >> +            t.append( "<li><b>" ).append( element.getName() ).append(
>> >> "</b> (" ).append( element.getType() )
>> >> +                .append( ") - " ).append( element.getUuid() );
>> >> +
>> >> +            Set<DataElementCategoryOptionCombo> optionCombos =
>> >> element.getCategoryCombo().getOptionCombos();
>> >> +            if ( optionCombos.size() > 1 )
>> >> +            {
>> >> +                t.append( "<br>CategoryOptionCombos\n<ul>\n" );
>> >> +                for ( DataElementCategoryOptionCombo optionCombo :
>> >> optionCombos )
>> >> +                {
>> >> +                    t.append( "<li><b>" ).append(
>> >> optionCombo.getName() ).append( "</b> - " )
>> >> +                        .append( optionCombo.getUuid() ).append(
>> >> "</li>" );
>> >> +                }
>> >> +                t.append( "</ul>\n" );
>> >> +            }
>> >> +            t.append( "</li>\n" );
>> >> +        }
>> >> +        t.append( "</ul>" );
>> >> +        xmlTemplate( t );
>> >> +        t.append( tail() );
>> >> +
>> >> +        return t.toString();
>> >> +    }
>> >> +
>> >> +    private String head( String title )
>> >> +    {
>> >> +        return "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"
>> >> \"http://www.w3.org/TR/html4/strict.dtd\";> \n<html><head><title>"
>> >> +            + title + "</title></head>\n" + "<body>\n<h1>" + title +
>> >> "</h1>\n";
>> >> +    }
>> >> +
>> >> +    private void xmlTemplate( StringBuilder t )
>> >> +    {
>> >> +        t.append( "<h2>Xml template</h2>\n" );
>> >> +
>> >> +        URI uri = uriInfo.getBaseUriBuilder().path(
>> >> "rpc/dataValueSets" ).build();
>> >> +        t.append( "<p>Post according to the following template to " );
>> >> +        t.append( "<a href=\"" ).append( uri ).append( "\">" ).append(
>> >> uri ).append( "</a>:</p>" );
>> >> +
>> >> +        t.append( "<pre>" ).append( "&lt;dataValueSet
>> >> xmlns=\"http://dhis2.org/schema/dataValueSet/0.1\"\n"; );
>> >> +        t.append( "    dataSet=\"dataSet UUID\" \n
>> >>  period=\"periodInIsoFormat\"\n    orgUnit=\"unit UUID\"" );
>> >> +        t.append( "\n    storedBy=\"user\"&gt;" );
>> >> +
>> >> +        t.append( "\n  &lt;dataValue dataElement=\"data element UUID\"
>> >> categoryOptionCombo=\"UUID, only specify if used\"
>> >> &gt;value&lt;/dataValue&gt;" );
>> >> +        t.append( "\n&lt;/dataValueSet&gt;" );
>> >> +        t.append( "</pre>" );
>> >> +    }
>> >> +
>> >> +    private String tail()
>> >> +    {
>> >> +        return "</body>\n</html>\n";
>> >> +    }
>> >> +
>> >> +    @Required
>> >> +    public void setDataValueSetMapper( DataValueSetMapper
>> >> dataValueSetMapper )
>> >> +    {
>> >> +        this.dataValueSetMapper = dataValueSetMapper;
>> >> +    }
>> >> +
>> >> +    @Required
>> >> +    public void setDataValueService( DataValueService dataValueService
>> >> )
>> >> +    {
>> >> +        this.dataValueService = dataValueService;
>> >> +    }
>> >> +
>> >> +    @Required
>> >> +    public void setDataSetService( DataSetService dataSetService )
>> >> +    {
>> >> +        this.dataSetService = dataSetService;
>> >> +    }
>> >> +
>> >> +}
>> >>
>> >> === modified file
>> >> 'dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml'
>> >> ---
>> >> dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml
>> >> 2011-01-21 18:28:26 +0000
>> >> +++
>> >> dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml
>> >> 2011-02-15 06:53:26 +0000
>> >> @@ -60,6 +60,9 @@
>> >>   <bean id="org.hisp.dhis.web.api.mapping.NotAllowedExceptionMapper"
>> >> class="org.hisp.dhis.web.api.mapping.NotAllowedExceptionMapper"
>> >>     scope="singleton" />
>> >>
>> >> +  <bean
>> >> id="org.hisp.dhis.web.api.mapping.IllegalArgumentExceptionMapper"
>> >> class="org.hisp.dhis.web.api.mapping.IllegalArgumentExceptionMapper"
>> >> +    scope="singleton" />
>> >> +
>> >>   <bean id="JacksonJaxbJsonProvider"
>> >> class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" scope="singleton"
>> >> />
>> >>
>> >>   <!-- ImportDataValue beans -->
>> >> @@ -76,6 +79,13 @@
>> >>   <bean id="org.hisp.dhis.web.api.service.ModelMapping"
>> >> class="org.hisp.dhis.web.api.service.ModelMapping">
>> >>     <property name="categoryService"
>> >> ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
>> >>   </bean>
>> >> +
>> >> +
>> >> +  <bean id="org.hisp.dhis.web.api.rpc.RPCResource"
>> >> class="org.hisp.dhis.web.api.rpc.RPCResource">
>> >> +    <property name="dataValueService"
>> >> ref="org.hisp.dhis.datavalue.DataValueService" />
>> >> +    <property name="dataValueSetMapper"
>> >> ref="org.hisp.dhis.importexport.datavalueset.DataValueSetMapper" />
>> >> +    <property name="dataSetService"
>> >> ref="org.hisp.dhis.dataset.DataSetService" />
>> >> +  </bean>
>> >>
>> >> </beans>
>> >>
>> >>
>> >> _______________________________________________
>> >> Mailing list: https://launchpad.net/~dhis2-devs
>> >> Post to     : dhis2-devs@xxxxxxxxxxxxxxxxxxx
>> >> Unsubscribe : https://launchpad.net/~dhis2-devs
>> >> More help   : https://help.launchpad.net/ListHelp
>> >
>> >
>> > _______________________________________________
>> > Mailing list: https://launchpad.net/~dhis2-devs
>> > Post to     : dhis2-devs@xxxxxxxxxxxxxxxxxxx
>> > Unsubscribe : https://launchpad.net/~dhis2-devs
>> > More help   : https://help.launchpad.net/ListHelp
>> >
>>
>> _______________________________________________
>> Mailing list: https://launchpad.net/~dhis2-devs
>> Post to     : dhis2-devs@xxxxxxxxxxxxxxxxxxx
>> Unsubscribe : https://launchpad.net/~dhis2-devs
>> More help   : https://help.launchpad.net/ListHelp
>
>



References