How to create a simple web app for a Vessel’s ETA API using python?

1. ETA and APIs

Estimated Time of Arrival or otherwise ETA is the most common term to know when a vessel arrives at its destination, usually known as port of call. Time is “estimated” alike other transportation mediums, as there can be delay due to bad weather conditions, vessel’s speed performance etc. ETA is so important for the prompt delivery of cargoes and liquid products as well as for the Suez and Panama transits.

Application Programming Interface (API) is one of the latest technology trends with the greatest advantage of making two different software talk to each other. Now mixing things with ETAs and APIs is very interesting as it gives us the power to develop our own web application. We can also choose the necessary information for our decision making and user needs.

2. Tools for the tutorial

In this tutorial, I will be introducing a simple way to create a simple web app the API of a vessel’s ETA. The call of API is a matter of few lines, which makes our life easier!

I am going to use the MarineTraffic API services and a visual web app builder Anvil based on extensively python for its web stack. For my coding practice and this tutorial, I find useful the python resources and practical lessons in Datacamp.

Using Anvil makes makes things more easy, as we can focus on the groundwork for our python code without worrying about the backend, a great advantage. Anvil is a freemium product, which allows us to experiment with our code and publish our app.

MarineTraffic provides real-time information on the movements of ships and the current location of ships in harbours and ports. I am using the API service Port Calls (EV01) which holds information on the vessel’s ETA, including the MMSI and IMO numbers and last port details.

For the MarineTraffic API, a user will need to purchase either Credits or a subscription (monthly or annually). Although there is no a freemium option, the great thing about MarineTraffic I can subscribe to an API and I can have it immediately.

Let’s start diving in!

3. Anvil set-up

An Anvil app contains the following:

  • A User Interface, where you can design your interface with a drag-and-drop builder
  • Client-side Python code, which runs in the web browser
  • Server-side Python code, connected to the Anvil’s servers
  • A built-in database (Data Tables), which stores your data on a like-spreadsheet table

I won’t spending time on how to get started, more information can be found here.

User interface

Anvil has a drag and drop builder which makes things more easy on the interface. For our tutorial we are using the following basic components:

  • Labels
  • Text boxes
  • Button
  • Data grid

By dragging and drop the necessary mentioned components in the section Client Code > Form1 the interface starts taking shape and looks like below.

For each of the component, we can use the Properties Panel to change properties of the selected component. As you can see on the left image, by clicking on the Button, we can complete its title in the Text property field. Similarly, for the Data Grid component, you fill in the Title for each column. We will talk more about the selection of columns from the API service on the next session.

Assigning a title and key to the column of data grid component

When the necessary titles are ready, the final version will look like the screenshot below. You don’t need to worry about the code in the interface for now. I will show you how to perform the necessary connections with the server code in the next section.

The interface of the app in Anvil

MarineTraffic API

Now that we have completed our interface, I am introducing the MarineTraffic API service that will use for the web app. This is the ETA to Port (VI07) and gets the latest arrivals and departures at a specific vessel in our case. To call the VI07 API, we need to know two things:

  • the upcoming port of call ID
  • Vessel ID

It becomes a little tricky how to acquire the port and ship IDs and here is the way how to access them quickly. In our tutorial, I am using the containership CMA CGM COLUMBA and port MARSAXLOKK in Malta. Once you search your desired vessel or port in MarineTraffic, you will notice in the URL its id. Here, the yellow boxes indicate their place in the URL.

When comes to the API response, MarineTraffic has two tier data levels . These are the simple and extended response. The extended response uses more credits.

For our web app, we just need the ETA of the current port – the simple response.

source MarineTraffic.com

Server Code

The requests library is the unique standard for making HTTP requests in Python. It removes the complexities of making requests behind a simple and beautiful API.

Since requests is already installed in the Anvil python framework, importing the library looks like this:

import requests

For the tutorial, we are importing also the below python libraries and objects. Since we are using the Anvil data tables, we will just need to call them.

from anvil.tables import app_tables
import anvil.tables.query as q
import anvil.tables as tables
import anvil.server
import datetime
import requests
import json

HTTP methods such as GET and POST, determine which action you’re trying to perform when making an HTTP request.

One of the most common HTTP methods is GET. The GET method indicates that you’re trying to get or retrieve data from a specified resource. To make a GET request, we use requests.get().

In the example case, I am using the API simple response:

  • Port ID
  • Ship ID
  • JSONO for the response type

The endpoint URL is the following:

response = requests.get(f"https://services.marinetraffic.com/en/api/etatoport/Enter your API key from MarineTraffic/portid:{port_id}/shipid:{ship_id}/protocol:jsono/msgtype:simple").json()[0]

The data columns that I have selected to pull out from the endpoint URL are the below. Also note that the assigned Keys (from the datagrid component – see section Interface) match the respective field name from the Simple response table. Our response is stored in the Anvil data table.

  • PORT_ID=port_id
  • SHIP_ID=ship_id
  • MMSI=response[‘MMSI’]
  • IMO=response[‘IMO’]
  • LAST_PORT=response[‘LAST_PORT’]
  • LAST_PORT_ID=response[‘LAST_PORT_ID’]
  • LAST_PORT_UNLOCODE=response[‘LAST_PORT_UNLOCODE’]
  • LAST_PORT_TIME=datetime.datetime.strptime(response[‘LAST_PORT_TIME’], “%Y-%m-%d %H:%M:%S”)
  • NEXT_PORT_NAME=response[‘NEXT_PORT_NAME’]
  • NEXT_PORT_UNLOCODE=response[‘NEXT_PORT_UNLOCODE’]
  • ETA_CALC=datetime.datetime.strptime(response[‘ETA_CALC’], “%Y-%m-%d %H:%M:%S”)

By completing the GET request and selecting the appropriate data columns, our code for the Server Code is:

@anvil.server.callable
def make_marine_request(port_id, ship_id):
  response = requests.get(f"https://services.marinetraffic.com/en/api/etatoport/Enter your API key from MarineTraffic/portid:{port_id}/shipid:{ship_id}/protocol:jsono/msgtype:simple").json()[0]
 
  app_tables.marine_test.add_row(
    PORT_ID=port_id,
    SHIP_ID=ship_id,
    MMSI=response['MMSI'],
    IMO=response['IMO'],
    LAST_PORT=response['LAST_PORT'],
    LAST_PORT_ID=response['LAST_PORT_ID'],
    LAST_PORT_UNLOCODE=response['LAST_PORT_UNLOCODE'],
    LAST_PORT_TIME=datetime.datetime.strptime(response['LAST_PORT_TIME'], "%Y-%m-%d %H:%M:%S"),
    NEXT_PORT_NAME=response['NEXT_PORT_NAME'],
    NEXT_PORT_UNLOCODE=response['NEXT_PORT_UNLOCODE'],
    ETA_CALC=datetime.datetime.strptime(response['ETA_CALC'], "%Y-%m-%d %H:%M:%S"),
    CREATED=datetime.datetime.utcnow()
  )
  
  return response


@anvil.server.callable
def get_marine_api_records():
  return app_tables.marine_test.search(tables.order_by("CREATED", ascending=False))

Client Code

Moving to the final step, the most important is to link the server and client code, so that they can talk to each other. This happens by:

  • Fill in the Ship ID and PortID in the text boxes
  • Clicking on the button
  • Adding the necessary API inputs into the data table.

To make this happen, we call submit_button_click function. In Anvil, its called as Events, same is located button component at the bottom of the properties:

Events for button component.

For the ship and port IDs, we simply assign them as textbox variables.

port_id = self.text_box_1.text
ship_id = self.text_box_2.text

Now let’s call our make_marine_request and get_marine_api.records server functions when the button is clicked, and pass in the user inputs to the data table. We made our server function available to our client-side code by decorating it as @anvil.server.callable.

This means we can call it from our client-side code using the anvil.server.call(‘make_marine_request) and anvil.server.call(‘get_marine_api_records’)

Now we can call both server functions from our submit_button_click function:

response = anvil.server.call('make_marine_request', port_id=port_id, ship_id=ship_id)
self.repeating_panel_1.items = anvil.server.call('get_marine_api_records')

An example in more detail can be found in the Anvil tutorials “Click events”. By completing Client Code step, our final version is:

from ._anvil_designer import GeneralTemplate
from anvil import *
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import anvil.server

class General(GeneralTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    
    self.repeating_panel_1.items = anvil.server.call('get_marine_api_records')

    # Any code you write here will run when the form opens.

  def button_1_click(self, **event_args):
    """This method is called when the button is clicked"""
    port_id = self.text_box_1.text
    ship_id = self.text_box_2.text
    response = anvil.server.call('make_marine_request', port_id=port_id, ship_id=ship_id)
    self.repeating_panel_1.items = anvil.server.call('get_marine_api_records')

  def text_box_1_pressed_enter(self, **event_args):
    """This method is called when the user presses Enter in this text box"""
    pass

  def text_box_2_pressed_enter(self, **event_args):
    """This method is called when the user presses Enter in this text box"""
    pass


Once we run our web application in Anvil.works and fill in the necessary inputs – the container ship CMA CGM COLUMBA and port MARSAXLOKK in Malta – we can see clearly the ETA of the vessel.

4. Final Notes

In this tutorial, I introduced how to create a simple web app by calling an API for a vessel’s ETA. Please free to raise your questions or comment in the comment box at the bottom. I would very glad to hear how it did go for you!

On our next tutorial, I will show you how to integrate an API and Google Maps in just a few lines using the Anvil Framework and MarineTraffic.com.

Leave a Comment

Your email address will not be published.