Kiedy wpadłem na pomysł stworzenia projektu AliTracker, pierwsze co pomyślałem: “Sprawdzę jak wygląda API, chociaż znając życie, poczta pewnie nie udostępnia API…”.
Następnie zdziwiłem się i ucieszyłem, ponieważ jest inaczej – nie do końca tak dobrze, jakby się chciało, ale przynajmniej w ogóle coś jest!Bowiem do API Poczty Polskiej można dotrzeć wyłącznie poprzez protokół SOAP, a ja przecież piszę aplikację w node.js i nasuwa się pytanie: czemu oni mi to robią? Cóż, nie ma co się nad tym zastanawiać, trzeba to po prostu zaimplementować.

Nigdy wcześniej z SOAP nie korzystałem (szczególnie przy pracy z node.js), więc zrobiłem mały research, okazało się, że jest taki npm package ‘soap’ i myślę sobie: “No dobra, jeden POST request będzie się wyróżniał, napiszę krótką funkcję i mam co trzeba”.

Zrobiłem wszystko zgodnie z wytycznymi dokumentacji, czytałem o WSSecurity, dowiedziałem się jak to poustawiać, przypadkiem odkryłem skąd wywoływać metody oferowane przez te API i mimo to, po kilku godzinach siedzenia nad kilkunastoma linijkami kodu, jedyna odpowiedź jaką uzyskałem od serwera to UNDEFINED. Po prostu jakaś masakra, zdesperowany przeczytałem tę archaiczną dokumentację od deski do deski. Oczywiście nic nowego z tego nie wynikło…

Następnie zacząłem analizować każdą funkcję, którą zaimportowałem z ‘soap’, każdy argument, każdy return i ostatecznie moją uwagę zwróciła właściwość funkcji ustawiającej WSSecurity, czyli hasTimeStamp, domyślnie ustawiona na true. Po krótkim rozeznaniu wiedziałem już z czym mam do czynienia, bowiem API PPSA nie posiada tego zabezpieczenia… Wyłączenie tej opcji spowodowało, że wreszcie uzyskałem sensowną odpowiedź od serwera!

Nie był to jednak powód do radości, gdyż obiekt jaki ujrzałem to chyba majstersztyk entropii..

{
  "return": {
    "attributes": {
      "xsi:type": "ax21:Przesylka"
    },
    "danePrzesylki": {
      "attributes": {
        "xsi:type": "ax21:DanePrzesylki"
      },
      "dataNadania": "2017-03-06T00:00:00.000Z",
      "kodKrajuNadania": "PL",
      "kodKrajuPrzezn": "PL",
      "kodRodzPrzes": "PX",
      "krajNadania": "POLSKA",
      "krajPrzezn": "POLSKA",
      "numer": "testp0",
      "rodzPrzes": "Pocztex - Przesyłka kurierska krajowa",
      "urzadNadania": {
        "attributes": {
          "xsi:type": "ax21:Jednostka"
        },
        "nazwa": "UP Białystok 1"
      },
      "urzadPrzezn": {
        "attributes": {
          "xsi:type": "ax21:Jednostka"
        },
        "nazwa": "UP Warszawa 18"
      },
      "zakonczonoObsluge": false,
      "zdarzenia": {
        "attributes": {
          "xsi:type": "ax21:ListaZdarzen"
        },
        "zdarzenie": [ //było tych zdarzeń znacznie więcej, ale wykasowałem, żeby nie scrollować 5min..
          {
            "attributes": {
              "xsi:type": "ax21:Zdarzenie"
            },
            "czas": "2017-03-07 08:22",
            "jednostka": {
              "attributes": {
                "xsi:type": "ax21:Jednostka"
              },
              "nazwa": "UP Warszawa 18"
            },
            "kod": "P_WD",
            "konczace": false,
            "nazwa": "Wydanie doręczycielowi"
          },
          {
            "attributes": {
              "xsi:type": "ax21:Zdarzenie"
            },
            "czas": "2017-03-07 10:22",
            "jednostka": {
              "attributes": {
                "xsi:type": "ax21:Jednostka"
              },
              "nazwa": "UP Warszawa 18"
            },
            "kod": "P_A",
            "konczace": false,
            "nazwa": "Awizo"
          },
          {
            "attributes": {
              "xsi:type": "ax21:Zdarzenie"
            },
            "czas": "2017-03-07 16:22",
            "jednostka": {
              "attributes": {
                "xsi:type": "ax21:Jednostka"
              },
              "nazwa": "UP Warszawa 18"
            },
            "kod": "P_D",
            "konczace": true,
            "nazwa": "Doręczenie",
            "przyczyna": {
              "attributes": {
                "xsi:type": "ax21:Przyczyna"
              },
              "kod": "P_D_TEST",
              "nazwa": "Testowa przyczyna zdarzenia"
            }
          }
        ]
      }
    },
    "numer": "testp0",
    "status": 0
  }
}

W związku z tym podjąłem się zadania normalizacji i tłumaczenia tego obiektu, no bo jak można, tak głęboko zagnieżdżać dane… Nie zajęło to na szczęście sporo czasu, ale przez to sprawdzanie przesyłek pocztowych stało się karkołomne już w samym kodzie, a nie wygląda to dobrze.

Na razie jednak kończę przygodę z API Poczty Polskiej i w chwili obecnej prezentuje się to następująco:

  app.post('/api/check', (req, res) => {
    const url = "https://tt.poczta-polska.pl/Sledzenie/services/Sledzenie?wsdl";
    soap.createClient(url, (err, client) => {
      if(err) { console.log(err); }
      client.setSecurity(new soap.WSSecurity('sledzeniepp', 'PPSA', {hasTimeStamp: false}));
      client.Sledzenie.SledzenieHttpSoap11Endpoint.sprawdzPrzesylke({numer: req.body.packageNumber}, (err, response) => {
        if(err) {console.log(err);}
        const { status } = response.return;
        if(status === 0) {
          const parcel = extractPackage(req.body.packageName, req.body.packageNumber, response.return.danePrzesylki);
          res.send(parcel);
        } else if(status === 1) {
          res.status(422).send({ error: "Istnieją różne przesyłki o podanym numerze." });
        } else {
          res.status(422).send({ error: "Brak przesyłki o podanym numerze." });
        }
      });
    });
  });

A aktualnie pracuję już nad wyświetlaniem danych w aplikacji, do następnego!