Rick

Rick
Rick

Friday, April 29, 2016

QBit Resourceful RESTful Microservices

You can build resourceful REST URIs using @RequestMapping from QBit microservices lib.
Typically you use HTTP GET to get a list of something and if you are returning more than one then the URI path should end with / as follows:

@RequestMapping("/department/")

    @RequestMapping("/department/")
    public List<Department> getDepartments() {
To add to a list, you would use a PUT or a POST. PUT is generally used for updates, and POST is used to create. If you were editing an object at a give ID you would use a PUT, but if you were adding a new item to a list, you would use a PUT to update a list or a POST to create an item. Dealers choice.

@RequestMapping(value = "/department/{departmentId}/", method = RequestMethod.POST)

@RequestMapping(value = "/department/{departmentId}/", method = RequestMethod.POST)
public boolean addDepartment(@PathVariable("departmentId") Integer departmentId,
                                  final Department department) {
You could easily get into a long drawn out argument about which to use PUT or POST in the above scenario, because you are updating the list (adding an item to it), but you are creating a department. Just remember POST for create, and PUT for update.
To get a single employee, you could use a path param. Some say that path params are nice for people and search engines, I say ok dude.

Using a path param @RequestMapping(value = "/department/{departmentId}/employee/{employeeId}", method = RequestMethod.GET)

    @RequestMapping(value = "/department/{departmentId}/employee/{employeeId}", method = RequestMethod.GET)
    public Employee getEmployee(@PathVariable("departmentId") Integer departmentId,
                                @PathVariable("employeeId") Long employeeId) {
HTTP GET is the default, but you can specify it as we did above.
There are other annotations that work the same way except the HTTP method is in the name of the param.
  • @POST
  • @PUT
  • @GET
You could rewrite the last examples like this.

Using the @POST, @PUT, @GET

    @GET("/department/")
    public List<Department> getDepartments() {

...
    @POST(value = "/department/{departmentId}/")
    public boolean addDepartment(@PathVariable("departmentId") Integer departmentId,
                                  final Department department) {


...


    @GET(value = "/department/{departmentId}/employee/{employeeId}")
    public Employee getEmployee(@PathVariable("departmentId") Integer departmentId,
                                @PathVariable("employeeId") Long employeeId) {
Making the method name also be the annotation name makes things a bit more compact, and a bit easier to read.
Here are some more Resourceful REST examples in QBit to ponder.

Resource based RESTful API for Microservices

package com.mammatustech.hr;



import io.advantageous.qbit.annotation.*;

import java.util.*;

@RequestMapping("/hr")
public class HRService {

    final Map<Integer, Department> departmentMap = new HashMap<>();


    @RequestMapping("/department/")
    public List<Department> getDepartments() {
        return new ArrayList<>(departmentMap.values());
    }

    @RequestMapping(value = "/department/{departmentId}/", method = RequestMethod.POST)
    public boolean addDepartment(@PathVariable("departmentId") Integer departmentId,
                                  final Department department) {

        departmentMap.put(departmentId, department);
        return true;
    }

    @RequestMapping(value = "/department/{departmentId}/employee/", method = RequestMethod.POST)
    public boolean addEmployee(@PathVariable("departmentId") Integer departmentId,
                               final Employee employee) {

        final Department department = departmentMap.get(departmentId);

        if (department ==  null) {
            throw new IllegalArgumentException("Department " + departmentId + " does not exist");
        }

        department.addEmployee(employee);
        return true;
    }

    @RequestMapping(value = "/department/{departmentId}/employee/{employeeId}", method = RequestMethod.GET)
    public Employee getEmployee(@PathVariable("departmentId") Integer departmentId,
                                @PathVariable("employeeId") Long employeeId) {

        final Department department = departmentMap.get(departmentId);

        if (department ==  null) {
            throw new IllegalArgumentException("Department " + departmentId + " does not exist");
        }

        Optional<Employee> employee = department.getEmployeeList().stream().filter(
                employee1 -> employee1.getId() == employeeId).findFirst();

        if (employee.isPresent()){
            return employee.get();
        } else {
            throw new IllegalArgumentException("Employee with id " + employeeId + " Not found ");
        }
    }


    @RequestMapping(value = "/department/{departmentId}/employee/{employeeId}/phoneNumber/",
            method = RequestMethod.POST)
    public boolean addPhoneNumber(@PathVariable("departmentId") Integer departmentId,
                                  @PathVariable("employeeId") Long employeeId,
                                  PhoneNumber phoneNumber) {

        Employee employee = getEmployee(departmentId, employeeId);
        employee.addPhoneNumber(phoneNumber);
        return true;
    }



    @RequestMapping(value = "/department/{departmentId}/employee/{employeeId}/phoneNumber/")
    public List<PhoneNumber> getPhoneNumbers(@PathVariable("departmentId") Integer departmentId,
                                             @PathVariable("employeeId") Long employeeId) {

        Employee employee = getEmployee(departmentId, employeeId);
        return employee.getPhoneNumbers();
    }


    @RequestMapping(value = "/kitchen/{departmentId}/employee/phoneNumber/kitchen/",
            method = RequestMethod.POST)
    public boolean addPhoneNumberKitchenSink(@PathVariable("departmentId") Integer departmentId,
                                  @RequestParam("employeeId") Long employeeId,
                                  @HeaderParam("X-PASS-CODE") String passCode,
                                             PhoneNumber phoneNumber) {

        if ("passcode".equals(passCode)) {
            Employee employee = getEmployee(departmentId, employeeId);
            employee.addPhoneNumber(phoneNumber);
            return true;
        } else {
            return false;
        }
    }



}
Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training