back

Abfall und Recycling Hamburg API Visaulisation

Abfall und Recycling Hamburg API Visualisation

As I have told in previous post, I would like to share some of projects I implement mostly for personal usage, fun and learning. Sooooo let's go!
- Problem: It was always hard for me to find the useful map with recycling bins quickly
- Tech: NextJS, Abfall und Recycling Hamburg API, Geolocation API, TailwindCSS, Pigeon Maps

Usage

- Select preferred recycling type in selector
- Request your location to navigate the map
- Browse the map

Stack

Planning went pretty quick, so I pointed out things I need to prepare before implementation. First thing I need is the Map Client - searching a bit, I have found a lightweight and simple Pigeon Maps. I already had an API and data types in mind to match everything, so decision was made. Regarding the tech stack, I went with usual and already handy NextJS - TailwindCSS.

Planning

I have also planned that structure-wise I would need following components: actual map that accepts marks to render on map and renders Pigeon Map, kind of a container/wrapper for map where all the needed logics (fetch API and state manipulations) is going to be placed, detached component for UI (select that I have mentioned before). I would not mention any other helpers, files for types and etc - those along with the full project you can find in the repository

Code

Going to the code, the solution was supposed to be pretty simple. I planned to have a lazy loaded map, selector to choose between recycling types, and useEffect that would fetch corresponding API path on selection change.
The main functionality looks like that:
const [type, setType] = useState<OptionType | "">("")
const [error, setError] = useState<string>("")
const [position, setPosition] = useState<Position>()
const [features, setFeatures] = useState<Array<FeatureType>>([])
useEffect(() => {
  if (type) {
    const apiUrl = getApiUrl(options[type])

    fetch(apiUrl)
      .then(res => res.json())
      .then(data => setFeatures(data.features))
      .catch((error) => setError(error || defaultError))
  } else {
    setFeatures([])
  } 
}, [type])
There is another useState hook for storing user current position in the component state. That was more like a nice-to-have feature I have decided to implement to try out different built-in APIs that I do not use in my regular work, unfortunately. By the way, usage is pretty simple:
export type Position = {
  coords: {
    latitude: number,
    longitude: number,
  }
}

const checkGeoPosition = () => {
  navigator.geolocation.getCurrentPosition((position: Position) => {
    setPosition(position)
  });
}
Anyway, let's get back to the main code:
1. type in state is for storing recycling type selection
2. error indicates if fetching went well
3. features are actual data returned from API (types are declared in root folder, so you may check if interested)
4. once type is changed we are requesting the data and set features to state
5. then we can simply provide fetched data to the map and render map marks in the corresponding coordinates
6. Voilá! That's it!

Providing the source code once again to not forget - https://github.com/Pulko/recycle
And live implementation here: https://www.recycle.pulko-app.com
Thank you for your time and bye bye :)