Group Abstract Group Abstract

Message Boards Message Boards

How to make an API that gives city data?

POSTED BY: Peter Burbery
27 Replies
POSTED BY: Peter Burbery

I also made a form that displays information for a city like a city's area and median age. I also made an API function to call from Mathematica at CloudObject["https://www.wolframcloud.com/obj/73c731cb-7afb-4b8b-ad06-509c3aab3dd1"]

POSTED BY: Peter Burbery

I built a page that displays information for date and time.

POSTED BY: Peter Burbery
POSTED BY: Peter Burbery
POSTED BY: Peter Burbery
Posted 3 years ago

The server uses the requesters IP address to decide which city to compute data for.

Yes, the geo location (lat/long), country, and city are determined in cloud by using a geo IP mapping that determines location from a public IP address. If the requester IP address is not a public address, there is no mapping, so the cloud sets these to a default location/country/city, which is that of the Wolfram company HQ in Champaign, Illinois for public cloud. For private clouds the default location is configurable.

I know the server has a static IP address but if people from different parts of the world queried the Wolfram Cloud API could it tell where they were?

The server static IP address doesn't enter in to the discussion at all. It tells where they come from using the IP and the geoIP mapping described above.

If things aren't working as expected in your testing with a VPN, you'd want to confirm that the request to the cloud is actually going through your VPN, and you'd want to see what requester IP address the cloud actually sees, and confirm that's what you expect.

POSTED BY: Joel Klein

I deploy an API. Someone in another part of the world makes a request to my API. The server uses the requesters IP address to decide which city to compute data for. I know the server has a static IP address but if people from different parts of the world queried the Wolfram Cloud API could it tell where they were?

POSTED BY: Peter Burbery
Posted 3 years ago

What is "the API's geolocation"? Do you mean the geolocation where the servers run? You might think you could discover the cloud's location by making an HTTP from within the cloud to itself, but the networking there is going to use a private IP address (aka RFC 1918 address), one that doesn't have a GeoIP mapping. We do have a notion of a default geolocation for the server, but I don't think we expose it in a WL variable, it gets assigned within the web server and then passed to WL. We could do that, and there is precedence for things like that, e.g. $SystemTimeZone is the time zone the computer has before a user (or the cloud) started localizing it.

POSTED BY: Joel Klein
Posted 3 years ago
POSTED BY: Joel Klein

Is there a way to make a programmatic API with a default that could be executed with for example HTTPRequest in Mathematica that defaults to the API's Geolocation if no parameters are specified and otherwise if a location is specified it uses that instead?

POSTED BY: Peter Burbery

I changed the code to remove the Delayed and it worked successfully:

CloudPublish[
 FormFunction[{"city" -> <|"Interpreter" -> "City", 
     "Input" :> $GeoLocationCity["Name"]|>}, 
  Grid[{{Style[#city["Name"], "Title"]}, {Style["Current Temperature",
        "Subsubsection"], 
      IconData["AirTemperature", WeatherData[#city, "Temperature"]], 
      QuantityForm[WeatherData[#city, "Temperature"], 
       "Abbreviation"]}, {Style["Map", "Subsubsection"], 
      GeoGraphics[EntityValue[#city, "Position"], 
       GeoBackground -> "VectorClassic", ImageSize -> Large]}, {Style[
       "Image", "Subsubsection"], 
      GeoImage[EntityValue[#city, "Position"], 
       ImageSize -> Large]}, {Style["High Resolution Image", 
       "Subsubsection"], 
      GeoImage[EntityValue[#city, "Position"], GeoZoomLevel -> 15, 
       ImageSize -> Large]}}, Alignment -> Left] &, "CloudCDF"], 
 Permissions -> "Public"]

Here's some pictures.enter image description hereenter image description here

POSTED BY: Peter Burbery
Posted 3 years ago
POSTED BY: Joel Klein
POSTED BY: Peter Burbery
Posted 3 years ago

Your problems getting the VPN IP to be picked up are a separate independent issue -- anything we talk about is going to use the GeoIP database. You can deploy this to check what IP and location is seen by cloud:

CloudDeploy[Delayed[{$RequesterAddress, $GeoLocation, $GeoLocationCountry, $GeoLocationCity}]] 

I asked the forms expert what the right way is to populate the field by default, which is to use the Input specification, like this example:

CloudPublish[
    FormFunction[{"country" -> <|"Interpreter" -> "Country", "Input" :> $GeoLocationCountry["Name"]|>}, 
        {"Country" -> #country, "Population" -> #country["Population"]} &
    ]
]
POSTED BY: Joel Klein
POSTED BY: Peter Burbery
Posted 3 years ago

There should be, and I think there could be both a programmatic way to do it and a UI way. Hannah provided a technique to collect this through a form, taking advantage of the fact that GenerateHTTPResponse can nest the active cloud object expressions like APIFunction and FormFunction within the same rest (in her case, an APIFunction that returns a FormFunction). But I think a programmatic way to do it, probably through a query parameter, is also needed and would have to have support added in to the cloud back end. I've put this on our to-do list of things to add to cloud.

POSTED BY: Joel Klein

I would also like to option that lets the user override the default city. I'm not sure if an api can have intereaction with a user or if the right function would be FormFunction to ask the user for a city and then give data but it seems like there should be a way to add manually overriding and defaults.

POSTED BY: Peter Burbery
POSTED BY: Peter Burbery

Here's a simple APIFunction that demonstrates one way to add a default for the current city:

CloudDeploy[APIFunction[{}, 
  FormFunction[{"location" -> <|"Label" -> "City", 
       "Input" -> 
        Replace[$GeoLocationCity, {e_Entity :> e["Name"], _ :> 
           "Your city here"}] , "Interpreter" -> "City"|>},
    LocalTime[#location] &, 
    AppearanceRules -> <|"Title" -> "Please enter a city"|>
    ] &
  ], CloudObject["getlocation.api"], Permissions -> "Public"]
POSTED BY: Hannah Clemens
Posted 3 years ago

Awesome, nice to see this!

POSTED BY: Joel Klein

I was able to change the map with some code:

CloudDeploy[
 Delayed[{LatitudeLongitude[$GeoLocation], 
   GeoGraphics[$GeoLocation, GeoRange -> Quantity[50, "Kilometers"], 
    ImageSize -> Large, GeoBackground -> "VectorClassic"]}], 
 CloudObject["myip.api"], Permissions -> "Public"]

enter image description here enter image description here

POSTED BY: Peter Burbery

Yes!!! It's working. Thank you!

POSTED BY: Peter Burbery
Posted 3 years ago

That looks like an error from a pre-release build of 13.2. You can work around it by passing a named object, like CloudObject["myip.api"], as the 2nd argument to CloudDeploy:

CloudDeploy[Delayed[$RequesterAddress], CloudObject["myip.api"]]

You may also be able to fix the problem by calling Needs["UUID`"].

POSTED BY: Joel Klein
POSTED BY: Peter Burbery
Posted 3 years ago
POSTED BY: Joel Klein

I now have a simple API that lets you enter a city and see basic weather data

CloudDeploy[FormFunction @@ 
  APIFunction[ "location" -> "ComputedLocation", 
   Grid[{{Style["Current Temperature", "Subsubsection"], 
       IconData["AirTemperature", 
        WeatherData[#location, "Temperature"]], 
       QuantityForm[WeatherData[#location, "Temperature"], 
        "Abbreviation"]}, {Style["Current Relative Humidity", 
        "Subsubsection"], 
       IconData["RelativeHumidity", 
        WeatherData[#location, "Humidity"]], 
       QuantityForm[WeatherData[#location, "Humidity"], 
        "Abbreviation"]}, {Style["Current Wind Speed", 
        "Subsubsection"], 
       IconData["WindSpeed", WeatherData[#location, "WindSpeed"]], 
       QuantityForm[WeatherData[#location, "WindSpeed"], 
        "Abbreviation"]}, {Style["Current Wind Direction", 
        "Subsubsection"], 
       IconData["WindDirection", 
        WeatherData[#location, "WindDirection"]], 
       QuantityForm[WeatherData[#location, "WindDirection"], 
        "Abbreviation"]}, {Style["Geographical position", 
        "Subsubsection"], FromDMS[#location], 
       DMSString[#location, "Position"]}, {Style["Current time", 
        "Subsubsection"], 
       DateString[Now, "DateTime"]}, {Style[
        "Geographical xyz position", "Subsubsection"], 
       GeoPositionXYZ[#location]}, {Style[
        "Geographical projected position with Bonne grid projection", 
        "Subsubsection"], 
       First[GeoGridPosition[#location, "Bonne"]]}}, 
     Alignment -> Left] & , "CloudCDF"], "versa"]
POSTED BY: Peter Burbery
POSTED BY: Peter Burbery
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard