diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml
index c164631f413..92cc3122446 100644
--- a/hapi-fhir-base/pom.xml
+++ b/hapi-fhir-base/pom.xml
@@ -5,7 +5,7 @@
+ * Validate is used to accept a resource, and test whether it would be acceptable for + * storing (e.g. using an update or create method) + *
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value=ElementType.METHOD) +public @interface Validate { + + /** + * The return type for this method. This generally does not need + * to be populated for a server implementation (using a {@link IResourceProvider}, + * since resource providers will return only one resource type per class, + * but generally does need to be populated for client implementations. + */ + // NB: Read, Search (maybe others) share this annotation, so update the javadocs everywhere + Class extends IResource> type() default IResource.class; + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index a19f4f99cfe..281a3845491 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -51,6 +51,7 @@ import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.client.BaseClientInvocation; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; @@ -139,8 +140,9 @@ public abstract class BaseMethodBinding { Update update = theMethod.getAnnotation(Update.class); Delete delete = theMethod.getAnnotation(Delete.class); History history = theMethod.getAnnotation(History.class); + Validate validate = theMethod.getAnnotation(Validate.class); // ** if you add another annotation above, also add it to the next line: - if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history)) { + if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate)) { return null; } @@ -188,6 +190,8 @@ public abstract class BaseMethodBinding { returnTypeFromAnnotation = create.type(); } else if (update != null) { returnTypeFromAnnotation = update.type(); + } else if (validate != null) { + returnTypeFromAnnotation = validate.type(); } if (returnTypeFromRp != null) { @@ -232,6 +236,8 @@ public abstract class BaseMethodBinding { return new DeleteMethodBinding(theMethod, theContext, theProvider); } else if (history != null) { return new HistoryMethodBinding(theMethod, theContext, theProvider); + } else if (validate != null) { + return new ValidateMethodBinding(theMethod, theContext, theProvider); } else { throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName()); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java index 5ff211f5c26..6c55c178ce0 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; import java.io.Writer; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Map; @@ -50,7 +49,6 @@ import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingUtil; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; @@ -220,12 +218,22 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding { if (!getResourceName().equals(theRequest.getResourceName())) { return false; } - if (StringUtils.isNotBlank(theRequest.getOperation())) { + if (getMatchingOperation() == null && StringUtils.isNotBlank(theRequest.getOperation())) { + return false; + } + if (getMatchingOperation() != null && !getMatchingOperation().equals(theRequest.getOperation())) { return false; } return true; } + /** + * For servers, this method will match only incoming requests + * that match the given operation, or which have no operation in the + * URL if this method returns null. + */ + protected abstract String getMatchingOperation(); + /** * Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete) */ diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java index 8c0ec871762..00b8e0dd241 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java @@ -41,7 +41,6 @@ import ca.uhn.fhir.rest.server.EncodingUtil; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOutcomeReturningMethodBinding { private int myResourceParameterIndex; @@ -63,8 +62,7 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu } if (resourceParameter == null) { - throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @" - + ResourceParam.class.getSimpleName()); + throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @" + ResourceParam.class.getSimpleName()); } } @@ -129,14 +127,20 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu theServer.addHapiHeader(theResponse); - theResponse.setContentType(Constants.CT_TEXT); - - Writer writer = theResponse.getWriter(); - try { - writer.append("Resource has been created"); - } finally { + if (response != null && response.getOperationOutcome() != null) { + theResponse.setContentType(encoding.getResourceContentType()); + Writer writer = theResponse.getWriter(); + try { + parser.encodeResourceToWriter(response.getOperationOutcome(), writer); + } finally { + writer.close(); + } + } else { + theResponse.setContentType(Constants.CT_TEXT); + Writer writer = theResponse.getWriter(); writer.close(); } + // getMethod().in } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/CreateMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/CreateMethodBinding.java index 3798136f894..75f01aa4a10 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/CreateMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/CreateMethodBinding.java @@ -64,4 +64,9 @@ public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe return new PostClientInvocation(getContext(), resource, urlExtension.toString()); } + @Override + protected String getMatchingOperation() { + return null; + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/DeleteMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/DeleteMethodBinding.java index 4af8c63646b..10153c4f6ad 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/DeleteMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/DeleteMethodBinding.java @@ -143,4 +143,11 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding { theParams[myIdParameterIndex] = new IdDt(id); } + + @Override + protected String getMatchingOperation() { + return null; + } + + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java index 3c417e562df..d3029655954 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java @@ -20,7 +20,6 @@ package ca.uhn.fhir.rest.method; * #L% */ -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashSet; @@ -36,11 +35,10 @@ import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; import ca.uhn.fhir.rest.client.GetClientInvocation; -import ca.uhn.fhir.rest.param.IParameter; import ca.uhn.fhir.rest.param.BaseQueryParameter; +import ca.uhn.fhir.rest.param.IParameter; import ca.uhn.fhir.rest.param.ParameterUtil; import ca.uhn.fhir.rest.server.Constants; -import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; @@ -134,6 +132,10 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding { ourLog.trace("Method {} doesn't match because request type is POST but operation is not _search: {}", theRequest.getId(), theRequest.getOperation()); return false; } + if (theRequest.getRequestType() != RequestType.GET && theRequest.getRequestType() != RequestType.POST) { + ourLog.trace("Method {} doesn't match because request type is {}", theRequest.getOperation()); + return false; + } Set* This exception will generally contain an {@link OperationOutcome} instance which details the failure. *
+ * + * @see InvalidRequestException Which corresponds to an HTTP 400 Bad Request failure */ public class UnprocessableEntityException extends BaseServerResponseException { diff --git a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java b/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java index 854a807af2f..fc5bf590148 100644 --- a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java +++ b/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java @@ -23,6 +23,7 @@ import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.OperationOutcome; import ca.uhn.fhir.model.dstu.resource.Organization; import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.StringDt; @@ -38,6 +39,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.annotation.VersionIdParam; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.client.ITestClient; @@ -307,6 +309,7 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) { } //END SNIPPET: create + //START SNIPPET: createClient @Create public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient); @@ -369,6 +372,39 @@ return retVal; +//START SNIPPET: validate +@Validate +public MethodOutcome validatePatient(@ResourceParam Patient thePatient) { + + /* + * Actually do our validation: The UnprocessableEntityException + * results in an HTTP 422, which is appropriate for business rule failure + */ + if (thePatient.getIdentifierFirstRep().isEmpty()) { + /* It is also possible to pass an OperationOutcome resource + * to the UnprocessableEntityException if you want to return + * a custom populated OperationOutcome. Otherwise, a simple one + * is created using the string supplied below. + */ + throw new UnprocessableEntityException("No identifier supplied"); + } + + // This method returns a MethodOutcome object + MethodOutcome retVal = new MethodOutcome(); + + // You may also add an OperationOutcome resource to return + // This part is optional though: + OperationOutcome outcome = new OperationOutcome(); + outcome.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("One minor issue detected"); + retVal.setOperationOutcome(outcome); + + return retVal; +} +//END SNIPPET: validate + + + + public static void main(String[] args) throws DataFormatException, IOException { //nothing } diff --git a/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml b/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml index 3f8a92dc99b..7e003ca0da7 100644 --- a/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml +++ b/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml @@ -9,26 +9,28 @@- RESTful Clients and Servers both share the same + RESTful Clients and Servers both share the same method pattern, with one key difference: A client is defined using annotated methods on an interface which are used to retrieve resources, - whereas a server requires concrete method implementations + whereas a server requires concrete method + implementations to actually provide those resources.
- +- Unless otherwise specified, the examples below show server + Unless otherwise specified, the examples below show + server implementations, but client methods will follow the same patterns.
- +- The following table lists the operations supported by + The following table lists the operations supported by HAPI FHIR RESTful Servers and Clients.
- +- Instance - Read + Instance - Read | Read the current state of the resource @@ -47,7 +49,7 @@ |
- Instance - VRead + Instance - VRead | Read the state of a specific version of the resource @@ -55,7 +57,7 @@ |
- Instance - Update + Instance - Update | Read the state of a specific version of the resource @@ -63,7 +65,7 @@ |
- Instance - Delete + Instance - Delete | Delete a resource @@ -71,7 +73,7 @@ |
- Instance - History + Instance - History | Retrieve the update history for a particular resource @@ -79,7 +81,7 @@ |
- Type - Create + Type - Create | Create a new resource with a server assigned id @@ -87,10 +89,10 @@ |
- Type - Search
+ Type - Search
|
@@ -99,7 +101,7 @@ |
- Type - Search + Type - Search | Search the resource type based on some filter criteria @@ -107,7 +109,7 @@ |
- Type - History + Type - History | Retrieve the update history for a particular resource type @@ -115,7 +117,7 @@ |
- Type - Validate + Type - Validate | Check that the content would be acceptable as an update @@ -123,7 +125,7 @@ |
- System - Conformance + System - Conformance | Get a conformance statement for the system @@ -131,7 +133,7 @@ |
- System - Transaction + System - Transaction | Update, create or delete a set of resources as a single transaction @@ -139,7 +141,7 @@ |
- System - History + System - History | Retrieve the update history for all resources @@ -147,31 +149,33 @@ |
- System - Search + System - Search | Search across all resource types based on some filter criteria |
- The - read + The + + read + operation retrieves a resource by ID. It is annotated with the @Read - annotation, and has a single parameter annotated with the + annotation, and has a single parameter annotated with the @IdParam annotation.
@@ -182,11 +186,12 @@
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient/111
- The - vread + The + + vread + operation retrieves a specific version of a resource with a given ID. It looks exactly like a "read" operation, but with a second - parameter annotated with the + parameter annotated with the @VersionIdParam annotation.
@@ -209,49 +216,53 @@ - +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient/111/_history/2
- The - update + The + + update + operation updates a specific resource instance (using its ID), and optionally - accepts a version ID as well (which can be used to detect version conflicts). + accepts a version ID as well (which can be used to detect version conflicts).
- Update methods must be annotated with the + Update methods must be annotated with the @Update - annotation, and have a parameter annotated with the + annotation, and have a parameter annotated with the @Resource annotation. This parameter contains the resource instance to be created.
- In addition, the method must have a parameter annotated with the + In addition, the method must have a parameter annotated with the @IdParam annotation, and optionally may have a parameter annotated with the @VersionIdParam
Update methods must return an object of type - MethodOutcome. This + MethodOutcome + . This object contains the identity of the created resource.
The following snippet shows how to define an update method on a server:
- +
Example URL to invoke this method (this would be invoked using an HTTP PUT,
- with the resource in the PUT body):
+ with the resource in the PUT body):
+
http://fhir.example.com/Patient
The following snippet shows how the corresponding client interface - would look: + would look:
- +- In the case of a server which is able to do version conflict checking, an + In the case of a server which is able to do version conflict checking, an extra parameter would be added:
- +- The - delete + The + + delete + operation retrieves a specific version of a resource with a given ID. It takes a single - ID parameter annotated with an + ID parameter annotated with an @IdParam annotation, which supplies the ID of the resource to delete.
@@ -305,61 +319,73 @@ - +Delete methods are allowed to return the following types:
void
, in which case
- the server will return an empty response and the client will ignore
+ void
+ : This method may return
+ void
+ , in which case
+ the server will return an empty response and the client will ignore
any successful response from the server (failure responses will still throw
- an exception)
+ an exception)
MethodOutcome
,
+
+ MethodOutcome
+
+ :
+ This method may return
+ MethodOutcome
+ ,
which is a wrapper for the FHIR OperationOutcome resource, which may optionally be returned
by the server according to the FHIR specification.
- Example URL to invoke this method (HTTP DELETE):
+ Example URL to invoke this method (HTTP DELETE):
+
http://fhir.example.com/Patient/111
- The - create - operation saves a new resource to the server, allowing the server to - give that resource an ID and version ID. + The + + create + + operation saves a new resource to the server, allowing the server to + give that resource an ID and version ID.
- Create methods must be annotated with the + Create methods must be annotated with the @Create - annotation, and have a single parameter annotated with the + annotation, and have a single parameter annotated with the @Resource annotation. This parameter contains the resource instance to be created.
Create methods must return an object of type - MethodOutcome. This + MethodOutcome + . This object contains the identity of the created resource.
The following snippet shows how to define a server create method:
- +
Example URL to invoke this method (this would be invoked using an HTTP POST,
- with the resource in the POST body):
+ with the resource in the POST body):
+
http://fhir.example.com/Patient
The following snippet shows how the corresponding client interface - would look: + would look:
- +The - search operation returns a bundle - with zero-to-many resources of a given type, matching a given set of parameters. + + search + + operation returns a bundle + with zero-to-many resources of a given type, matching a given set of parameters.
- +The following example shows a search with no parameters. This operation should return all resources of a given type (this obviously doesn't make - sense in all contexts, but does for some resource types). + sense in all contexts, but + does for some resource types).
- +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient
To allow a search using given search parameters, add one or more parameters - to your search method and tag these parameters as either + to your search method and tag these parameters as either @RequiredParam or - @OptionalParam. + @OptionalParam + .
- +- This annotation takes a "name" parameter which specifies the parameter's + This annotation takes a "name" parameter which specifies the parameter's name (as it will appear in the search URL). FHIR defines standardized parameter names for each resource, and these are available as constants on the - individual HAPI resource classes. + individual HAPI resource + classes.
- +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient?family=SMITH
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient?identifier=urn:foo|7000135
Search methods may take multiple parameters, and these parameters
may be optional. To add a second required parameter, annotate the
- parameter with
- @RequiredParam.
- To add an optional parameter (which will be passed in as null
if no value
+ parameter with
+ @RequiredParam
+ .
+ To add an optional parameter (which will be passed in as
+ null
+ if no value
is supplied), annotate the method with
- @OptionalParam.
+ @OptionalParam
+ .
You may annotate a method with any combination of as many @RequiredParam and as many @OptionalParam - parameters as you want. It is valid to have only @RequiredParam parameters, or + parameters as you want. It is valid to have only @RequiredParam + parameters, or only @OptionalParam parameters, or any combination of the two.
- +
- Example URLs to invoke this method:
- http://fhir.example.com/Patient?family=SMITH
+ Example URLs to invoke this method:
+
+ http://fhir.example.com/Patient?family=SMITH
+
http://fhir.example.com/Patient?family=SMITH&given=JOHN
It is possible to accept multiple values of a single parameter as well. This is useful in cases when you want to return a list - of resources with criteria matching a list of possible values. - See the FHIR Specification + of resources with criteria matching a list of + possible values. + See the + FHIR Specification for more information.
- +The FHIR specification allows two types of composite parameters:
?language=FR,NL
) this is treated as an OR relationship, and
- the search should return elements matching either one or the other.
+ Where a parameter may accept multiple comma separated values within a single value string
+ (e.g.
+ ?language=FR,NL
+ ) this is treated as an
+ OR
+ relationship, and
+ the search should return elements matching either one or the other.
?language=FR&language=NL
) this is treated as an AND relationship,
- and the search should return only elements matching both.
+ Where a parameter may accept multiple value strings for the same parameter name
+ (e.g.
+ ?language=FR&language=NL
+ ) this is treated as an
+ AND
+ relationship,
+ and the search should return only elements matching both.
To accept a composite parameter, use a parameter type which implements the IQueryParameterOr interface. For example, to accept searches for Observations matching any of a collection of names:
- +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Observation?name=urn:fakenames|123,urn:fakenames|456
To accept a composite parameter, use a parameter type which implements the IQueryParameterAnd interface.
- +- See the section below on date ranges for + See the section below on + date ranges + for one example of an AND parameter.
- +The FHIR specification provides a sytax for specifying - dates (and date/times as well, but for simplicity we will just say dates here) + dates (and date/times as well, but for simplicity we will just say dates here) as search criteria.
- Dates may be optionally prefixed with a qualifier. For example, the
- string >=2011-01-02
means any date on or after 2011-01-02.
-
>=2011-01-02
+ means any date on or after 2011-01-02.
+
+
To accept a qualified date parameter, use the QualifiedDateParam - parameter type. + parameter type.
- +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Observation?birthdate=>=2011-01-02
Invoking a client of thie type involves the following syntax:
- +- A common scenario in searches is to allow searching for resources - with values (i.e timestamps) within a range of dates. + A common scenario in searches is to allow searching for resources + with values (i.e timestamps) within a range of dates.
FHIR allows for multiple parameters with the same key, and interprets
- these as being an "AND" set. So, for example, a range of
- DATE >= 2011-01-01
and DATE < 2011-02-01
+ these as being an "AND" set. So, for example, a range of
+
+ DATE >= 2011-01-01
+ and
+ DATE < 2011-02-01
+
can be interpreted as any date within January 2011.
The following snippet shows how to accept such a range, and combines it with a specific identifier, which is a common scenario. (i.e. Give me a list - of observations for a specific patient within a given date range) -
+ of observations for a + specific patient within a given date range) +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Observation?subject.identifier=7000135&date=>=2011-01-01&date=<2011-02-01
Invoking a client of this type involves the following syntax:
- +FHIR allows clients to request that specific linked resources be included as contained resources, which means that they will be "embedded" in a special - container called "contained" within the parent resource. + container called + "contained" within the parent resource.
- +HAPI allows you to add a parameter for accepting includes if you wish to support them for specific search methods. @@ -652,79 +718,141 @@ - +
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/DiagnosticReport?subject.identifier=7000135&_include=DiagnosticReport.subject
- FHIR supports named queries, + FHIR supports + named queries + , which may have specific behaviour defined. The following example shows how to create a Search - operation with a name. + operation with a name.
- +This operation can only be invoked by explicitly specifying the given query name - in the request URL. Note that the query does not need to take any parameters. + in the request URL. Note that the query does not need to take any parameters.
- Example URL to invoke this method:
+ Example URL to invoke this method:
+
http://fhir.example.com/Patient?_query=namedQuery1&someparam=value
- Not yet implemented + The + + validate + + tests whether a resource passes business validation, and would be + acceptable for saving to a server (e.g. by a create or update method). +
++ Validate methods must be annotated with the + @Validate + annotation, and have a parameter annotated with the + @Resource + annotation. This parameter contains the resource instance to be created. +
++ Validate methods may optionally also have a parameter + oftype IdDt annotated with the + @IdParam + annotation. This parameter contains the resource ID (see the + FHIR specification + for details on how this is used) +
++ Validate methods must return normally if the resource validates successfully, + or throw an + UnprocessableEntityException + or + InvalidRequestException + if the validation fails. +
++ Validate methods must return either: +
++ The following snippet shows how to define a server validate method: +
+ +
+ Example URL to invoke this method (this would be invoked using an HTTP POST,
+ with the resource in the POST body):
+
+ http://fhir.example.com/Patient/_validate
FHIR defines that a FHIR Server must be able to export a conformance statement, which is an instance of the Conformance resource describing the server itself.
- +The HAPI FHIR RESTful server will automatically export such a conformance statement. See the RESTful Server documentation for more information.
- +If you wish to override this default behaviour by creating your own metadata provider, you simply need to define a class - with a method annotated using the + with a method annotated using the @Metadata annotation.
@@ -732,11 +860,11 @@ - +- To create a Client which can retrieve a Server's conformance + To create a Client which can retrieve a Server's conformance statement is simple. First, define your Client Interface, using - the @Metadata annotation: + the @Metadata annotation:
Then use the standard - RESTful Client mechanism for instantiating + RESTful Client + mechanism for instantiating a client:
Not yet implemented
- - + +Not yet implemented
- - + +- The - history - operation retrieves a historical collection of all versions of a single resource - (instance history), all resources of a given type (type history), - or all resources of any type on a server (server history). + The + + history + + operation retrieves a historical collection of all versions of a single resource + (instance history) + , all resources of a given type + (type history) + , + or all resources of any type on a server + (server history) + .
- History methods must be annotated with the + History methods must be annotated with the @History annotation, and will have additional requirements depending on the kind of history method intended:
The following snippet shows how to define a history method on a server:
- +The following snippet shows how to define various history methods in a client.
- +