Java REST API + cURL + python3

During the next lines, I am going to implement a very simple REST API using JavaEE 7 and Java SE 8 technologies, maven as build tool and GlassFish as application server. I am going to test this API with cURL and, I am going to consume this API using python3 using the Requests module.

Java EE 7 REST API

First, we need to create a maven project in our favorite IDE and add our dependencies to the pom.xml file

...
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.5.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <finalName>apicrud</finalName>
</build>
...

Second, we are going to create a persistence.xml file. In this case, we are not interested in how to configure a DB, then, we are going to use the default datasource that GlassFish provides us as default “jdbc/__default“. With all of this in mind, the file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="ApiCrudPU" transaction-type="JTA">
        <jta-data-source>jdbc/__default</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
        </properties>
    </persistence-unit>
</persistence>

Now, we need to create our Entity. In this case, I have chosen a simple one, User with three attributes:

  • id: Autogenerated id to identify the user.
  • name: User’s name.
  • email: User’s email.

The result should be something like:

package com.wordpress.binarycoders.apicrud;

import java.io.Serializable;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table (name = "users")
@NamedQueries ({
    @NamedQuery (name = User.FIND_ALL, query = "SELECT u FROM User u")
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    public static final String FIND_ALL = "User.findAll";
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Column(name = "name")
    private String name;
    
    @Column(name = "email")
    private String email;

    /* Getters, Setters, equals and hashCode methods */    
}

The next step, it is to implement the boundary or service layer. Being a simple example, we can skip this layer, but I like to implement everything for learning purposes. This layer is going to be very simple, only the necessary object to perform the operation in the DB and the basic operations to implement a CRUD. The result looks like:

package com.wordpress.binarycoders.apicrud;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.validation.constraints.NotNull;

@Stateless
public class UserService {
    
    @PersistenceContext
    private EntityManager em;
    
    public void create(@NotNull User user) {
        this.em.persist(user);
    }
    
    public User findById(@NotNull Long id) {
        return this.em.find(User.class, id);
    }
    
    public List<User> findAll() {
        TypedQuery<User> typedQuery = this.em.createNamedQuery(User.FIND_ALL, User.class);

        return typedQuery.getResultList();
    }
    
    public void update(@NotNull User user) {
        this.em.merge(user);
    }
    
    public void delete(@NotNull Long id) {
        this.em.remove(this.findById(id));
    }
}

To do all of this available to the world, we need to implement our REST API, and for this, we need to configure the REST capabilities in our system, piece of cake with the last version of Java EE. We just need to create a class to enable these capabilities:

package com.wordpress.binarycoders.apicrud;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rs")
public class ApplicationConfig extends Application {
    
}

And, finally, we need to implement our REST layer with the four actions that are going to allow us to perform the CRUD operations:

package com.wordpress.binarycoders.apicrud;

import java.net.URI;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
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.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

@Path("/users")
@Produces ({ MediaType.APPLICATION_JSON })
@Consumes ({ MediaType.APPLICATION_JSON })
@Stateless
public class UserEndPoint {
    
    @EJB
    private UserService service;
    
    @Context
    private UriInfo uriInfo;
    
    @GET
    public Response findAll() {
        List<User> users = this.service.findAll();
        
        GenericEntity<List<User>> list = new GenericEntity<List<User>>(users) {};
        
        return Response.ok(list).build();
    }
    
    @GET
    @Path("/{id}")
    public Response findById(@PathParam("id") Long id) {
        User user = this.service.findById(id);
        
        if (user == null) {
            throw new NotFoundException();
        }
        
        return Response.ok(user).build();
    }
    
    @POST
    public Response create(User user) {
        this.service.create(user);
        
        URI uri = uriInfo.getAbsolutePathBuilder().path(String.valueOf(user.getId())).build();
        
        return Response.created(uri).build();
    }
    
    @PUT
    public Response update(User user) {
        this.service.update(user);
        
        return Response.ok().build();
    }
    
    @DELETE
    @Path("/{id}")
    public Response delete(@PathParam("id") Long id) {
        this.service.delete(id);
        
        return Response.noContent().build();
    }
}

I think that in this point, assuming that everyone reading this, it is a developer and this is not an entry level post, all of you should be capable to understand everything has been written in the above lines. If there are things that you do not know or you do not understand due to a lack of information or your knowledge is not enough (all of us have been there), look at the note at the end of this post.

cURL test

Now, obviously, we need to test if our REST API is working properly. For this, we can implement some solution based on test frameworks or manual code but, due to the simplicity of the object User, it is enough with the cURL tool. To test our API we are going to perform these operations:

  • Select all the users
  • Create a user
  • Select the created user
  • Update the user
  • Delete the user

These operations can be performed with the next commands:

curl -i -H "Content-Type: application/json" http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" -X POST -d '{"name":"john","email":"john@example.org"}' http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" http://localhost:8080/ApiCRUD/rs/users/1
curl -i -H "Content-Type: application/json" -X PUT -d '{"id”:1,”name":"John Doe","email":"john.doe@example.org"}' http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" -X DELETE http://localhost:8080/ApiCRUD/rs/users/1

Everything should look well, and the appropriate HTTP codes should be received.

Python3 client

The last step today, it is to implement a very very simple python3 client to consume our API. This is going to be a basic script to invoke the CRUD operations available in the API.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

URL = 'http://localhost:8080/ApiCRUD/rs/users'

def getUsers():
	print('Get users...\n')

	response = requests.get(URL)

	assert response.status_code == 200

	users = response.json()
	print(json.dumps(users, indent = 4, separators = (',', ':')))

def getUser(location):
	print('Get single user ...\n')

	response = requests.get(location)

	assert response.status_code == 200

	users = response.json()
	print(json.dumps(users, indent = 4, separators = (',', ':')))

def createUser():
	print('Creating user...\n')

	headers = {'content-type': 'application/json'}
	user = {"name": "John Doe", "email": "john.doe@example.org"}
	response = requests.post(URL, data = json.dumps(user), headers = headers)

	assert response.status_code == 201

	print('Location: ' + response.headers['location'])

	return response.headers['location']

def updateUser(location):
	print('Updating user...')

	loc = location.split('/')

	headers = {'content-type': 'application/json'}
	user = {"id": loc[-1], "name": "Jane Doe", "email": "jane.doe@example.org"}
	response = requests.put(URL, data = json.dumps(user), headers = headers)

	assert response.status_code == 200

def deleteUser(location):
	print('Deleting user...')

	response = requests.delete(location)

	assert response.status_code == 204

	print('Checking delete operation')
	response = requests.get(location)

	assert response.status_code == 404

def main():
	getUsers()
	location = createUser()
	getUser(location)
	updateUser(location)
	getUser(location)
	deleteUser(location)

if __name__ == "__main__":
	main()

And that’s all. Now, we have a little REST AP, a python3 client and a basic knowledge about how to use cURL to test it.

See you.

You can find the code for the REST API available here.

Note: All the content in this post will be splitter and explained in future post, one for each one of the three big point explained in here: Java EE 7 REST API creation, cURL test and python3 REST client.

Advertisements
Java REST API + cURL + python3

Python port scanner

Today, we are going to implement a simple port scanner implemented in python 3. The code is quite simple, and I think that it doesn’t need any explanation.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from functools import partial
from multiprocessing import Pool
import socket
import optparse

DEFAULT_CORE_NUMBER = 2


def ping(host, port):
    try:
        socket.socket().connect((host, port))
        return port
    except socket.error as err:
        return False


def scanPorts(host, ports, cores):
    p = Pool(cores)
    ping_host = partial(ping, host)

    return filter(bool, p.map(ping_host, ports))


def main():
    parser = optparse.OptionParser('%prog -t <target host> -p <target port(s)> -n <number of cores>')
    parser.add_option('-t', dest='host', type='string', help='Specify the target host')
    parser.add_option('-p', dest='ports', type='string', help='Specify the target port(s); Separate them by commas.')
    parser.add_option('-n', dest='cores', type='int', help='Specify the number of CPU cores do you want to use.')

    (options, args) = parser.parse_args()

    if (options.host == None):
        print(parser.usage)
        exit(0)
    else:
        host = str(options.host)

    if (options.ports == None):
        ports = range(1, 65536)
    else:
        ports = list(map(int, str(options.ports).split(',')))

    if (options.cores == None):
        cores = DEFAULT_CORE_NUMBER
    else:
        cores = options.cores

    print('\nScanning ports on ' + host + ' ...')

    portsScanned = list(scanPorts(host, ports, cores))

    print(str(len(portsScanned)) + ' ports available.')
    print(portsScanned)

    print('\nDone.')


if __name__ == "__main__":
    main()

The script has three different options:

  • -t: Specify the target host. It is a mandatory option.
  • -p: Specify target ports.
  • -n: Specify the number of cores that are going to be used.

We can see some invocation examples:

scanner.py
scanner.py -t 127.0.0.1
scanner.py -t 127.0.0.1 -p 21,80 -n 2

See you.

Python port scanner