Contents


Building a REST service with integrated web services server for IBM i, Part 3

Deploying a RESTful application using multiple HTTP methods

Comments

For several years now, IBM i users have had the ability to deploy ILE programs and services programs as web services based on the SOAP protocol using the integrated web services server support that is part of the operating system. REST web services was not supported by the integrated web services server, until now.

This article is the third in a series of articles about the integrated web services server REST support.

  • Part one starts out by explaining the basic concepts behind REST web services and how the integrated web services server supports REST services.
  • Part two takes you through the steps of deploying a simple ILE application as a RESTful web service.
  • In part three, we take you through the steps of deploying a more complex ILE application that uses more of the REST features.

Prerequisites

Software

In order to get all the PTFs required by the integrated web services server in support of REST, you need to load the latest HTTP Group PTF. Table 1 lists the HTTP group PTFs that are needed for each of the supported releases of the IBM i operating system.

Table 1. Software prerequisites
IBM i release HTTP Group PTF
i 7.2 SF99713 (level 6 or greater)
i 7.1 SF99368 (level 32 or greater)

Assumptions

Before reading this article, you should have read Part one of the article in the series in order to have a basic understanding of REST principles and the terminology used.

You can find links to various information on REST in the Resources section. You should also be familiar with the fundamental concepts of JavaScript Object Notation (JSON) and XML.

The RESTful application

The example used in this discussion is a sample Student Registration Application (SRA). The student registration management functions provided in this sample SRA application enable you to:

  • Register new students
  • Edit information for a registered students
  • List registered students
  • Remove student registrations

SRA consists of a service program, STUDENTRSC, that contain the RESTful services (that is, procedures) that provides the basic Create-Read-Update-Delete (CRUD) database logic, and a database file, STUDENTDB, where student records are stored.

Listing 1 shows a partial listing of the source for the application that shows the prototypes of the procedures to be exported from the STUDENTRSC service program (the RESTful resource).

Listing 1. Partial listing of the SRA application
h NOMAIN PGMINFO(*PCML:*MODULE:*DCLCASE)

D studentRec      DS                  qualified template
D  studentID                     9A
D  firstName                    50A
D  lastName                     50A
D  gender                       10A

D getAll          PR
D  students_...
D  LENGTH                       10i 0
D  students                           likeds(studentRec) dim(1000)
D                                     options(*varsize)
D  httpHeaders                 100a   dim(10)

D getByID         PR
D  studentID                     9a   const
D  student                            likeds(studentRec)
D  httpStatus                   10i 0
D  httpHeaders                 100a   dim(10)

D create          PR       
D  student                            likeds(studentRec)
D  httpStatus                   10i 0
D  httpHeaders                 100a   dim(10)

D update          PR       
D  student                            likeds(studentRec)
D  httpStatus                   10i 0

D remove          PR       
D  studentID                     9a   const
D  httpStatus                   10i 0

The resource program object defines the following five procedures:

  • getAll: Get all students.
  • getById: Get a particular student using the student ID.
  • create: Create a new student record.
  • update: Update a student's record.
  • remove: Delete a particular student's record.

You should also note that a data structure template (studentRec) defines the fields in the database file. You can optionally define the data structure using an externally described data structure, but the decision to not use an externally defined data structure is due to wanting to control the case of the XML element names and/or the JSON field names, which are obtained from the generated program interface information. Previously, element and field names were all capitalized. However, a new feature was introduced and fixed in IBM i 7.1 (PTF SI55340) and IBM i 7.2 (PTF SI55442) that allows you to control the case by specifying the *DCLCASE parameter for the PGMINFO control specification keyword. When specified, the names in the program interface information will be generated in the same case as the names defined in the RPG source file.

Things to get done before deployment

As we have done in Part 2 of the series, we need figure out things before actually deploying the RESTful web service. To summarize, when deploying a RESTful web service, you should have answers to the following questions at the bare minimum:

  1. How do I want the Uniform Resource Identifier (URIs) to look like?
  2. What HTTP methods will the resource support?
  3. What incoming content types should be supported?
  4. What type of data should be returned?

In the following sections, go through these basic questions in the context of the application that will be deployed. Table 2 shows a summary of the mappings that we want between the HTTP methods and the URIs for the SRA application.

Table 2. HTTP method and URI mappings
HTTP method URI Description
GET /context-root/students Return all student registrations
GET /context-root/students/{id} Return student registration
POST /context-root/students Register a new student
PUT /context-root/students Update registered student
DELETE /context-root/students/{id} Remove registered student

Note: The default context-root for an integrated web services server is /web/services.

Return all student registrations

Listing 2 shows the getAll() procedure. This procedure is used to return all student registrations and will be mapped to the HTTP GET method.

Listing 2. Procedure getAll()
P getAll          B                   EXPORT
D getAll          PI
D  students_...
D  LENGTH                       10i 0
D  students                           likeds(studentRec) dim(1000)
D                                     options(*varsize)
D  httpStatus                   10i 0
D  httpHeaders                 100a   dim(10)
 /FREE
 clear httpHeaders;
 clear students;
 students_LENGTH = 0;

 openStudentDB();

 setll *loval STUDENTDB;

 read(e) studentR;
 if (%ERROR);
  httpStatus = H_SERVERERROR;
  return;
 endif;

 dow (NOT %eof);
  students_LENGTH = students_LENGTH+1;
  students(students_LENGTH).studentID =  studentID;
  students(students_LENGTH).firstName =  firstName;
  students(students_LENGTH).lastName  =  lastName;
  students(students_LENGTH).gender    =  gender;

  read(e) studentR;
  if (%ERROR);
    httpStatus = H_SERVERERROR;
    return;
  endif;
 enddo;

 httpStatus = H_OK;
 httpHeaders(1) = 'Cache-Control: no-cache, no-store';

 closeStudentDB();
 /END-FREE
P getAll          E

Notice that in the parameter list, there is an array that contains the student records and a corresponding length field that indicates the number of student registration records in the array. If you do not specify the length field, the response will include empty elements which would degrade performance in both the client and the server.

The httpStatus parameter is used for the HTTP status code that is returned to the client. On unexpected errors, the HTTP status code H_SERVERERROR (500) is returned. Otherwise, H_OK (200) is returned.

The httpHeaders parameter is used to return the HTTP headers. In this example, we do not want the response cached and thus the Cache-Control HTTP header is set.

Return student registration

Listing 3 shows the getByID() procedure. This procedure is used to return a student registration and is mapped to the HTTP GET method.

Listing 3. Procedure getByID()
P getByID         B                   EXPORT
D getByID         PI
D  studentID                     9a   const
D  student                            likeds(studentRec)
D  httpStatus                   10i 0
D  httpHeaders                 100a   dim(10)
 /FREE
 clear httpHeaders;
 clear student;

 openStudentDB();

 chain(e) studentID STUDENTDB;
 if (%ERROR);
  httpStatus = H_SERVERERROR;
  return;
 elseif %FOUND;
  student.studentID = studentID;
  student.firstName = firstName;
  student.lastName  = lastName;
  student.gender    = gender;

  httpStatus = H_OK;
 else;
  httpStatus = H_NOTFOUND;
 endif;

 httpHeaders(1) = 'Cache-Control: no-cache, no-store';

 closeStudentDB();
 /END-FREE
P getByID         E

The studentID parameter is an input parameter that is used as a key to read the student registration from the database. If not found, the HTTP status code H_NOTFOUND (404) is returned. The caching control HTTP header is also set so the response is not cached.

Register a new student

Listing 4 shows the create() procedure. This procedure is used to create a new student registration and is mapped to the HTTP POST method.

Listing 4. Procedure create()
P create          B                   EXPORT
D create          PI        
D  student                            likeds(studentRec)
D  httpStatus                   10i 0
D  httpHeaders                 100a   dim(10)
 /FREE
 openStudentDB();

 studentID = student.studentID;
 firstName = student.firstName;
 lastName  = student.lastName;
 gender    = student.gender;

 write(e) studentR;
 if NOT %ERROR;
  httpStatus = H_CREATED;
  httpHeaders(1) = 'LOCATION: ' + 'http://server/web/service/students/' + studentID;
 elseif %STATUS = ERR_DUPLICATE_WRITE;
  httpStatus = H_CONFLICT;
 else;
  httpStatus = H_SERVERERROR;
 endif;

 closeStudentDB();
 /END-FREE
P create          E

If the student ID already exists in the database, an HTTP status code of H_CONFLICT (409) is returned. An HTTP status code of H_CREATED (201) is returned when the new registration is successfully created. For HTTP 201 status code responses, the Location HTTP is returned and is set to the URI of the new resource that was created by the request.

Update a registered student

Listing 5 shows the update() procedure. This procedure is used to update an existing student registration and is mapped to the HTTP PUT method.

Listing 5. Procedure update()
P update          B                   EXPORT
D update          PI   
D  student                            likeds(studentRec)
D  httpStatus                   10i 0
 /FREE
 openStudentDB();

 chain(e) student.studentID STUDENTDB;
 if (%ERROR);
  httpStatus = H_SERVERERROR;
  return;
 elseif %FOUND;
  studentID = student.studentID;
  firstName = student.firstName;
  lastName  = student.lastName;
  gender    = student.gender;

  update(e) studentR;
  if NOT %ERROR;
    httpStatus = H_NOCONTENT;
  else;
    httpStatus = H_NOTFOUND;
  endif;
 else;
  httpStatus = H_NOTFOUND;
 endif;

 closeStudentDB();
 /END-FREE
P update          E

If the student ID is not found, an HTTP status code of H_NOTFOUND (404) is returned. On a successful update operation, the HTTP status code of H_NOCONTENT (204) is retuned because the procedure does not return any data.

Remove a registered student

Listing 6 shows the remove() procedure. This procedure is used to remove an existing student registration and is mapped to the HTTP DELETE method.

Listing 6. Procedure remove()
P remove          B                   EXPORT
D remove          PI    
D  studentID                     9a   Const
D  httpStatus                   10i 0
 /FREE
 openStudentDB();

 chain(e) studentID STUDENTDB;
 if (%ERROR);
  httpStatus = H_SERVERERROR;
  return;
 elseif %FOUND;
  delete(e) studentR;
  if NOT %ERROR;
    httpStatus = H_NOCONTENT;
  elseif NOT %FOUND;
    httpStatus = H_NOTFOUND;
  else;
    httpStatus = H_SERVERERROR;
  endif;
 else;
  httpStatus = H_NOTFOUND;
 endif;

 closeStudentDB();
 /END-FREE
P remove          E

If the student ID is not found, an HTTP status code of H_NOTFOUND (404) is returned. On a successful delete operation, the HTTP status code of H_NOCONTENT (204) is returned because the procedure does not return any data.

What you need

The example REST API developed in this article assumes a database of student registrations and focuses on allowing you to retrieve, add, delete, and update these student registrations using normal REST conventions.

If you want to re-create the steps on your server, the source of the SRA application is available in the Download section.

Step 1. Set up the application database file

In this example, the STUDENTDB DB file is created in the STUDENTRSC library. To create the library, run the following CL command:

CRTLIB STUDENTRSC

To create the table, run the following SQL command:

CREATE TABLE STUDENTRSC/STUDENTDB
 ("Student ID"  FOR COLUMN studentID CHAR (9) NOT NULL,   
  "First Name"  FOR COLUMN firstName CHAR (50) NOT NULL,
  "last Name"   FOR COLUMN lastName  CHAR (50) NOT NULL,
  "Gender Type" FOR COLUMN gender CHAR (10) NOT NULL,
  PRIMARY KEY ( studentID ))
  RCDFMT studentr

To populate the table with sample student registration data, run the following SQL command:

INSERT INTO STUDENTRSC/STUDENTDB
 (studentID, firstName, lastName, gender)
 VALUES('823M934LA', 'Nadir', 'Amra', 'Male'),
       ('826M660CF', 'John', 'Doe', 'Male'),
       ('747F023ZX', 'Jane', 'Amra', 'Female')

Step 2. Create the integrated web services server

To deploy an ILE program object as a REST service, you need to have an integrated web services server created, and it must be version 2.6 or greater. If you have one already created, you can skip this section. If you need to create one, see Part two of this series of articles to learn how to create a server.

Step 3. Deploy the ILE application as a RESTful web service

Now, we deploy the SRA application service program as a RESTful web service. The STUDENTRSC service program is located in the STUDENTRSC library.

Step 3-1. Deploy an IBM i program object as a web service

Click Deploy New Service on the navigation bar to start the wizard to deploy a new web service.

Figure 1. Deploy web service – step 1

On the Deploy New Service page, you can either deploy a SOAP or a REST web service (see Figure 1). Because we are deploying a REST web service, we have selected the REST option.

Click Next.

Step 3-2. Specify the location of the IBM i program object

We now need to specify (see Figure 2) an ILE program object name from which the web service is generated. There are two ways to locate the program object on the system. The default way is to specify the program and library names by selecting the Specify IBM i library and ILE object name (Recommended) option. Another way is to search for the program object by browsing the integrated file system (IFS), which might take some time if the specified directory contains a lot of objects, such as /QSYS.LIB.

Figure 2. Deploy web service – step 2

Fill in library name as studentsrc and ILE Object name of studentsrc and click Next.

Step 3-3. Specify a name for the resource (web service)

Now we need to give the web service (the RESTful resource) a meaningful service name and description. By default, the service name and description is set to the name of the selected program object (see Figure 3).

Figure 3. Deploy web service – step 3

The resource name has been changed to students. In addition, you have the ability to set a URI path template for the resource. For this example, we do not need to specify anything because the path to the resource after changing the resource name is:

/context-root/students

Then, click Next.

Step 3-4. Select export procedures to externalize as resource methods

The next screen shows a list of exported procedures (see Figure 4). For service programs (object type of *SRVPGM), there might be one or more procedures. For programs (object type of *PGM), there is only one procedure, which is the main entry point to the program. Expanding the procedure row shows the parameters for the procedure and various parameter attributes.

Figure 4. Deploy web service – step 4

The parameter attributes are modifiable. In most cases, you want to modify the parameter attributes to control what data is to be sent by web service clients and what data is to be returned in the responses to the client requests.

In Figure 4, the REMOVE procedure is the procedure that is to be used to remove a student registration. It has two parameters, studentID and httpStatus. The studentID parameter is the identifier of the student to be removed and thus is an input parameter to the procedure. The httpStatus parameter is the HTTP status code to be returned in response to the client and is designated as an output parameter.

If you scroll down the Export procedures section you can see the UPDATE, CREATE, and GETBYID procedures (see Figure 5). The parameters have been designated as input or output parameters.

Figure 5. Deploy web service – step 4 (update, create, and getByID)

Scrolling down a little bit more, you can find the GETALL procedure (see Figure 6) that returns all the student registration data in the database.

Figure 6. Deploy web service – step 4 (getAll)

If we provide values as shown in Figure 6, then a request handled by the procedure returns a response that contains 1000 student records in which 3 student records contain student registration data, and 997 student records will be empty. Because we want to only return the actual number of registered students, the count column for the students parameter is changed to reference the students_LENGTH parameter (see Figure 7). This parameter is set by the GETALL procedure to the actual number of registered students, resulting in the response containing data for only the actual number of registered students.

Figure 7. Deploy web service – step 4 (getAll) modified

Click Next.

Step 3-5. Specify resource method information

Before discussing this step, it is a good idea to summarize the REST information for the RESTful application that is to be deployed. Table 3 summarizes the REST information for each of the resource methods (that is, procedures) of the SRA application.

Table 3: REST information for each procedure
REMOVEURL/context-root/students/{id}
MethodDELETE
Request bodyNone
Returns204 No content
404 Not found
500 Server error
UPDATEURL/context-root/students
MethodPUT
Request bodyJSON
Returns204 No content
404 Not found
500 Server error
CREATEURL/context-root/students
MethodPOST
Request bodyJSON
Returns201 Created
409 Conflict
500 Server error
GETBYIDURL/context-root/students/{id}
MethodGET
Request bodyNone
Returns200 OK & JSON
404 Not found
500 Server error
GETALLURL/context-root/students
MethodGET
Request bodyNone
Returns200 OK & JSON
500 Server error

The first procedure to be processed is the REMOVE procedure.

Figure 8. Deploy web service – step 5 (REMOVE)

Looking at Figure 8, you see that:

  • The HTTP request method (1) is set to DELETE.
  • Recall from Table 3 that the URI has the following format:
    /context-root/students/{id}
    That is, the student identifier information is passed in as part of the URI. Therefore, we specify a URI path template (2) so that any HTTP DELETE request that matches the URI will be passed to the REMOVE procedure. Notice that a regular expression \w{9} is used to ensure the registration ID is a word character that has a length of 9.
  • There is no entity body returned by the procedure, so the output media type does not matter. In this case, we select JSON (3) although we could have left the default of XML or JSON.
  • We have indicated that the httpStatus parameter (4) is to be used as the HTTP response code because the procedure will be returning a response code.
  • We want to inject the URI path variable id into the studentID parameter. We do this by specifying the input source as *PATH_PARAM (5) and selecting the identifier to be inserted.

Click Next to process the UPDATE procedure (Figure 9).

Figure 9. Deploy web service – step 5 (UPDATE)

Looking at Figure 9, you can find that:

  • The HTTP request method (1) is set to PUT.
  • The format of the input data is JSON (2).
  • There is no entity body returned by the procedure. As in Figure 8, we choose JSON (3) although we could have left the default of XML or JSON.
  • We have indicated that the httpStatus parameter (4) is to be used as the HTTP response code because the procedure will be returning a response code.

Click Next to process the CREATE procedure (Figure 10).

Figure 10. Deploy web service – step 5 (CREATE)

Looking at Figure 10, you can find that:

  • The HTTP request method (1) is set to POST.
  • The format of the input data is JSON (2).
  • There is no entity body returned by the procedure. Again we choose JSON (3), although we could have left the default of XML or JSON.
  • We have indicated that the httpStatus parameter (4) is to be used as the HTTP response code because the procedure will be returning a response code.
  • We have indicated that the procedure will be returning HTTP headers (5). Recall that the HTTP location header is set when a student registration is created successfully.

Click Next to process the GETBYID procedure (Figure 11).

Figure 11. Deploy web service – step 5 (GETBYID)

Looking at Figure 11, you can find that:

  • The HTTP request method (1) is set to GET.
  • Recall from Table 3 that the URI has the following format:
    /context-root/students/{id}
    That is, the student identifier information is passed in as part of the URI. Therefore, we specify a URI path template (2) so that any HTTP GET request that matches the URI will be passed to the GETBYID procedure. Notice that a regular expression \w{9} is used to ensure that the registration ID is a word with a length of 9 characters.
  • The format of the output data is JSON (3).
  • We have indicated that the httpStatus parameter (4) is to be used as the HTTP response code because the procedure will be returning a response code.
  • We have indicated that the procedure will be returning HTTP headers (5). Recall that the HTTP caching header is set when a student registration is returned.
  • We want to inject the URI path variable id into the studentID parameter. We do this by specifying the input source as *PATH_PARAM (6) and selecting the identifier to be inserted.

Click Next button to process the GETALL procedure (Figure 12).

Figure 12. Deploy web service – step 5 (GETALL)

Looking at Figure 12, you can find that:

  • The HTTP request method (1) is set to GET.
  • The format of the output data is JSON (2).
  • We have indicated that the httpStatus parameter (3) is to be used as the HTTP response code because the procedure will be returning a response code.
  • We have indicated that the procedure will be returning HTTP headers (4). Recall that the HTTP caching header is set when a student registration is returned.

At this point, we have completed setting REST information. Click Next.

Step 3-6. Specify user ID for this service

We now need to specify the user ID that the service will run under. As shown in Figure 13, you can run the service under the server's user ID or you can specify an existing user ID that the service will run under.

Figure 13. Deploy web service – step 6

In order for the web service to run correctly, the user ID status must be set to *ENABLED and the password must be set to a value other than *NONE. If a user ID is specified that is disabled or has a password of *NONE, a warning message is displayed and the service might not run correctly. In addition, ensure that the specified user ID has the proper authorities to any resources and objects that the program object needs, such as libraries, databases, and files.

In this example, we will accept the default. Click Next.

Step 3-7. Specify library list

Specify any library that the program object needs to function properly (see Figure 14).

Figure 14. Deploy web service – step 7

You have the option of placing the libraries at the start of the user portion of the library list or at the end of the user portion of the library list. Click Next.

Step 3-8. Specify transport information to be passed

Specify what transport information related to the client request is to be passed to the web service implementation code (see Figure 15). The information is passed as an environment variable.

Figure 15. Deploy web service – step 8

The transport metadata REMOTE_ADDR is passed to web service implementation code in an environment variable named REMOTE_ADDR.

HTTP headers indicate what transport headers (for example, HTTP headers) to pass to the web service implementation code. Transport headers are passed as environment variables. The environment variable name for HTTP headers is made up of the specified HTTP header prefixed with 'HTTP_', all in upper case. For example, if 'Content-type' is specified, then the environment variable name would be 'HTTP_CONTENT-TYPE'. If an HTTP header was not passed to the web service request, the environment variable value will be set to the null string.

Click Next.

Step 3-9. Deploy web service – step 9

The web service deployment wizard shows you a summary page (see Figure 16), giving you a chance to see the details relating to the web service being deployed.

Figure 16. Deploy web service – step 9 (Summary)

Clicking Finish at the bottom of the summary page will begin the installation process. When the web service is deployed, the deployed service becomes active (see the green dot to the left of the service name) as in Figure 17.

Figure 17. Successfully deployed RESTful web service

Congratulations, you have now successfully deployed an ILE program object as a RESTful web service.

Unlike SOAP, there is no test client provided by the IBM Web Administration GUI to test the REST service. Resource methods that are bound to the HTTP GET method could be tested by using a browser. Figure 18 shows the result of the request that returns all registered students.

Figure 18. Testing web service – return all registered students

Figure 19 shows the result of a request for a student record with a student ID of 823M934LA.

Figure 19. Testing web service – return a registered student

To test the other resource methods, an external tool (such as SoapUI) must be used, Figure 20 shows the result of a request to create a new student registration using SoapUI.

Figure 20. Testing web service – create a new student registration

Looking at Figure 20, because we are attempting to create a new student registration the HTTP method is POST (1). The sub panel numbered (2) is the new student registration data in the JSON format that will be sent to the server as part of the HTTP POST request. After submitting the request, that server response did not return any JSON data (3). Because the create request succeeded, the REST service returned the HTTP status code of 201 (Created) and a location header that contains the URL of the newly created student registration resource (4).

Summary

In Part one of this series, you learned the basic concepts behind REST web services and how the integrated web services server supports REST services. In Part two of this series, you learned how to deploy a simple ILE application as a RESTful web service. In this article, you learned how to deploy a more complex ILE application that uses more of the REST features.

The integrated web services server REST support provides a solid foundation for creating and deploying REST APIs based on ILE programs or service programs on the IBM i platform. Add the highly intuitive IBM Web Administration for i GUI for deploying web services, and you've got everything you need to quickly prototype and deploy your own custom REST API. So what are you waiting for?

Download

Description Name Size
Source code IBMi.REST.SRA.Src.zip 4 KB

Resources

  • For everything about the integrated Web services support on IBM i see the product web page.
  • Part one starts out by explaining the basic concepts behind REST web services and how the integrated web services server supports REST services.
  • Part two takes you through the steps of deploying a simple ILE application as a RESTful web service.
  • See RESTful Web services: The basics to learn what REST is all about.
  • See developerWorks: Learn about REST for articles, tutorials, standards, and other technical resources about REST web services.
  • For information about the HTTP protocol and content negotiation, see RFC 2616.
  • For information about Java regular expressions, see the Java Tutorials provided lesson on regular expressions.

Downloadable resources


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=IBM i
ArticleID=1005286
ArticleTitle=Building a REST service with integrated web services server for IBM i, Part 3
publish-date=05082015