Skip to main content

NHS Number client

Find out about our simple client and java code library, designed to make it easier to model NHS Numbers in software.

Overview of the format of an NHS Number

Domain rules state that NHS Numbers must:

  • be 10 digits long
  • consist solely of the numerals 0 through 9
  • be numbered from left to right.
  • start with the number 1, not 0, as most Java, C or .NET programmers might expect
  • end in a 10 - the check digit

Some combinations of the first 9 digits are impermissible.

For convenience, we’ve written an open source java client that implements some of these rules. The client is such that it can be used either as a standalone program (in which case, it produces results in TSV format for ease of use with standard POSIX tools) or as a java library (jar). To make things as easy as possible, we’ve also written some wrappers for POSIX and Debian/Ubuntu.

Your choices, in order of decreasing convenience, are:

  • Debian/Ubuntu deb packages
  • a tar ball, which contains a complete file system to untar over your root / - these should work on any POSIX system, including Mac OS X and Cygwin
  • a standalone java jar, with all dependencies included, suitable for execution or as a library
  • a set of java code libraries with source
  • forking from GitHub

Making requests

The best way to get going is to use the command line. We’ll look later on how to create requests programmatically using the java library.

Using the command line client to make requests

The way you do this varies depending on what you used above.

If you’ve installed the deb package or the tar ball, you’ll have the program hdn-number-client on your PATH. To use it, open a terminal console and type hdn-number-client. It takes standard POSIX options.

If you’ve installed the standalone jar file, you’ll need to run commands from the from the folder you downloaded the file to. Open a terminal console and change folder to the folder it is in. Type java -jar hdn-number-client.jar. It takes the same standard POSIX options as the program above. For the rest of this document, wherever you see hdn-number-client … you can substitute java -jar hdn-number-client.jar …

If you’ve downloaded or forked source from github, you can use IntelliJ to run the main class. Open source\subprojects.ipr and run the main class uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint. There are already some sample configurations set up for you to debug in IntelliJ. If you don’t have or use IntelliJ (and really should) then you can open in Eclipse or NetBeans. You’ll need to add the libraries ‘annotations’ (library/annotations/VERSION/annotations.jar) and ‘jopt-simple’ (library/jopt-simple/VERSION/jopt-simple-VERSION.jar) to the class path.

Checking everything is correct

Before we get going, let’s check that everything works as expected. Run the command hdn-number-client –help (remember to substitute java -jar hdn-number-client.jar if you need to). You should see a list of supported options. At the time of writing, it looks like this:

Option                              Description              
------                              -----------              
--create-check-digit <9 digits to   Ronseal option 2         
  generate check digit for>                                  
--help                              Displays help for options
--validate <10 digit NHS number to  Ronseal option 1         
  validate>                                                  
--version                           Displays version

If the output seems a bit compressed, it’s because we’re formatting for a 40 character wide screen – useful if you’re running this over ssh on Android. Whilst you can’t see it above, help output always produces an exit code of 1.

Since the options are regular POSIX long options (and are named similarly to those in the GNU coding standards), we can abbreviate them. Hence hdn-number-client -h and hdn-number-client –he will produce the same output. The only time you can’t do this is if the abbreviation would be ambiguous.

Let’s try out one of those options: –version.

Checking the version installed

Let’s run hdn-number-client –version:

 

hdn-number-client 2013.03.05.1047-development
© Crown Copyright 2013
 
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
 
    http://www.apache.org/licenses/LICENSE-2.0
 
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 
Written by Raphael Cohn ([email protected])

Standard GNU-like stuff. It’s worth understanding the version number, in this case, 2013.03.01.1537-development. The part before the hyphen is the timestamp of the last git check in used to build the binary – you should be able to find it using git log. Additionally, this should match the version of the deb package. The part after is the git branch the code was built from. Usually this will be either development or master.

If instead it says unknown version then it means you’re using code you’ve compiled yourself or wasn’t released ‘officially’.

Calculating a check digit

If you’ve got 9 digits, then you have a nearly valid NHS number. To use it in other systems, you’ll need all 10 digits – you need to calculate the check digit.

We can do that. Let’s say your number is 123456788, then we could run:

hdn-number-client --create-check-digit 123456788

Which produces a single line, LF-terminated to standard out (stdout) which contains the full 10 digit number:

1234567881

In this case, the check digit is 1. The exit code in this case is 0. If you just want the check digit, then you could use cut on POSIX systems to get it:

hdn-number-client --create-check-digit 123456788 | cut -b10

Which gives you just:

1

The output is also friendly to using with bash and environment variables. For instance, you might have a snippet in a script like this:

NHS_NUMBER="$(hdn-number-client --create-check-digit 123456788)"
echo "$NHS_NUMBER"

As mentioned earlier, not all potential NHS numbers are valid. For instance, what happens if the 9 digits are not a valid sequence?

Let’s see what happens with a slightly different 9 digits, 123456789:

hdn-number-client --create-check-digit 123456789

We get an exit code of 1 and a stack trace explanation on standard error (stderr, also known as 2):

 

java.lang.IllegalStateException: NHS Number 123456789 (supposedly without check digit) was invalid because 'Incorrect number 123456789, could not calculate check digit'
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.generateNhsNumberWithCheckDigit(HdnNumberClientConsoleEntryPoint.java:90)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.execute(HdnNumberClientConsoleEntryPoint.java:57)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:340)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:67)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:61)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.main(HdnNumberClientConsoleEntryPoint.java:25)
Caused by: uk.nhs.hdn.common.digits.IncorrectNumberCouldNotCalculateCheckDigitIllegalStateException: Incorrect number 123456789, could not calculate check digit
    at uk.nhs.hdn.number.NhsNumberExtractingCheckDigitCalculator.validateDigit(NhsNumberExtractingCheckDigitCalculator.java:66)
    at uk.nhs.hdn.number.NhsNumberExtractingCheckDigitCalculator.calculateCheckDigit(NhsNumberExtractingCheckDigitCalculator.java:45)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.generateNhsNumberWithCheckDigit(HdnNumberClientConsoleEntryPoint.java:86)
    ... 5 more

The stack trace gives a hint at how the java library might work – we can look at that latter.

It’s worth pointing out that separators and anything not a digit is not allowed. For instance:

hdn-number-client --create-check-digit 123-456-788

Produces a different error message to that above:

java.lang.IllegalStateException: NHS Number 123-456-788 (supposedly without check digit) was invalid because 'digit must be between 0 and 9'
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.generateNhsNumberWithCheckDigit(HdnNumberClientConsoleEntryPoint.java:90)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.execute(HdnNumberClientConsoleEntryPoint.java:57)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:340)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:67)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:61)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.main(HdnNumberClientConsoleEntryPoint.java:25)
Caused by: java.lang.IllegalArgumentException: digit must be between 0 and 9
    at uk.nhs.hdn.common.digits.Digit.digit(Digit.java:125)
    at uk.nhs.hdn.common.digits.Digit.digitFromUtf16Code(Digit.java:141)
    at uk.nhs.hdn.common.digits.Digits.<init>(Digits.java:70)
    at uk.nhs.hdn.common.digits.Digits.digits(Digits.java:52)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.generateNhsNumberWithCheckDigit(HdnNumberClientConsoleEntryPoint.java:84)
    ... 5 more

Verifying a check digit

Let’s say we want to validate the number 1234567881. We might run:

hdn-number-client --validate 1234567881

This seems to do very little, just returning the number as a LF-terminated line on standard out:

1234567881

Indeed the format is deliberately identical to that for generating check digits, giving a degree of substitutability.

So what’s the point? Well the exit code is set to 0, which is what bash, test et al interpret as ‘true’ or ‘success’:

hdn-number-client --validate 1234567881
echo $?

Gives:

1234567881
0

This makes sense if we return an exit code of 1 for an incorrect number. Let’s try validating 1234567890:

hdn-number-client --validate 1234567890

Which gives a stack trace on standard error of:

java.lang.IllegalStateException: NHS Number 1234567890 (supposedly with check digit) was invalid because 'Incorrect number 1234567890, could not calculate check digit'
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.validateNhsNumber(HdnNumberClientConsoleEntryPoint.java:73)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.execute(HdnNumberClientConsoleEntryPoint.java:50)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:340)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:67)
    at uk.nhs.hdn.common.commandLine.AbstractConsoleEntryPoint.execute(AbstractConsoleEntryPoint.java:61)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.main(HdnNumberClientConsoleEntryPoint.java:25)
Caused by: uk.nhs.hdn.common.digits.IncorrectNumberCouldNotCalculateCheckDigitIllegalStateException: Incorrect number 1234567890, could not calculate check digit
    at uk.nhs.hdn.number.NhsNumberExtractingCheckDigitCalculator.validateDigit(NhsNumberExtractingCheckDigitCalculator.java:66)
    at uk.nhs.hdn.number.NhsNumberExtractingCheckDigitCalculator.calculateCheckDigit(NhsNumberExtractingCheckDigitCalculator.java:45)
    at uk.nhs.hdn.common.digits.AbstractExtractingCheckDigitCalculator.guardCheckDigitCorrect(AbstractExtractingCheckDigitCalculator.java:67)
    at uk.nhs.hdn.common.digits.AbstractCheckDigitNumber.<init>(AbstractCheckDigitNumber.java:38)
    at uk.nhs.hdn.number.NhsNumber.<init>(NhsNumber.java:45)
    at uk.nhs.hdn.number.NhsNumber.valueOf(NhsNumber.java:40)
    at uk.nhs.hdn.number.client.HdnNumberClientConsoleEntryPoint.validateNhsNumber(HdnNumberClientConsoleEntryPoint.java:69)
... 5 more

And sets the exit code to 1:

hdn-number-client --validate 1234567890 2>/dev/null
echo $?

Gives:

1


Using the java library to make requests programmatically

The way you do this varies depending on what you used above:

  • if you’ve downloaded or forked source from github, you can use IntelliJ. Open source/subprojects.ipr and start hacking
  • if you’ve downloaded the jars (and source zips), create a project or add them to an existing project in your favourite IDE (if it isn’t IntelliJ, then switch now)

You can either add the hdn-number-client.jar as is (simple option), or, for more refinement and better integration with other HDN tools, its dependent jar files:

  • number
  • common-digits
  • and the third-party library annotations.jar. This is a compile-time only dependency

This list may change. To find the most up-to-date list, either extract META-INF/MANIFEST.MF from hdn-number-client.jar and read the Class-Path entry, or open the IntelliJ project (source/subprojects.ipr) and look at the dependencies of the module dbs-request-client (sensibly, module names match jar names and source zip names). Note that you’ll not need the common-commandLine module (jar) or jopt-simple library.

Modelling NHS Numbers

The ‘guts’ of the java library’s API is the class NhsNumber. It’s in the package uk.nhs.hdn.number.

The simplest way to create NhsNumber is to use the static valueOf method:

final NhsNumber nhsNumber = NhsNumber.valueOf("1234567881");

Sometimes NHS Numbers are used with separators such as space or hyphen. valueOf supports these too, provided they delineate the standard 3-3-4 pattern of digits.

final NhsNumber nhsNumberWithSpaceSeparators = NhsNumber.valueOf("123 456 7881");
final NhsNumber nhsNumberWithHyphenSeparators = NhsNumber.valueOf("123-456-7881");

You’ll get an IllegalArgumentException if the number’s format is not understood.

In addition, the number’s check digit is also computed and compared with the tenth digit parsed. If they don’t match, an IllegalArgumentException is thrown.

It’s possible to format a NHS number for display purposes. To get it with spaces, use the formattedForDisplay method:

final String fomattedWithSpaceSeparatorsForHumanDisplay = nhsNumber.formattedForDisplay();

Any other separator, such as a hyphen, can be specified:

final String fomattedWithHyphenSeparatorsForHumanDisplay = nhsNumber.formattedForDisplay('-');

Calculating check digits

This uses the class NhsNumberExtractingCheckDigitCalculator. It’s in the package uk.nhs.hdn.number.

The normal way to use it is to do as follows:

final Digits nineDigits = Digits.digits("123456788");
final Digit digit = NhsNumberExtractingCheckDigitCalculator.NhsNumberExtractingCheckDigitCalculatorInstance.calculateCheckDigit(nineDigits);

Digit is a class that models, as an enum, the digits 0 to 9. Digits is a class that models a sequence of Digit.

If it is impossible to calculate a check digit (as some sequences are unpermitted), an IncorrectNumberCouldNotCalculateCheckDigitIllegalStateException will be thrown.

Last edited: 12 August 2021 12:05 pm