CORS – golang – gorilla/handlers

gorilla/handlers - CORS

Dzisiejszy wpis został wymuszony przez zaistniałą sytuację. Powrócił bowiem jak bumerang problem, który zignorowałem wcześniej. Stąd też rozprawka zatytułowana: CORS – golang, która jest opisem problemu z Cross-Origin Resource Sharing na serwerze w języku Go.

Trochę teorii

CORS (Cross-Origin Resource Sharing) to technologia pozwalająca na wykonywanie asynchronicznych zapytań do każdego miejsca w sieci. Warunek jest jeden, musimy dostać zgodę na używanie zasobów tego miejsca.

Cross-origin resource sharing (w skrócie CORS) – mechanizm umożliwiający współdzielenie zasobów pomiędzy serwerami znajdującymi się w różnych domenach. Ściślej rzecz biorąc chodzi o możliwość wykonywania żądań AJAX między takimi serwerami przy zachowaniu pewnych ograniczeń co do dopuszczalnego źródła żądania. – za wikipedią

CORS – goolang

U mnie problem wystąpił w momencie wysyłania danych z formularza na wcześniej przygotowany endpoint.

CORS - golang - 404 Not found

Nasze zapytanie zostaje przerwane w momencie wysyłania OPTIONS, dostajemy status 404 Not Found. Dodatkowo w konsoli dostajemy poniższy komunikat:

XMLHttpRequest cannot load http://localhost:8001/product. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 404.

Diagnoza

Błąd ewidentnie wskazuje na problem z CORSem. W celu przyspieszenia pracy nad API, poszedłem na pewne uproszczenia w konfiguracji. Dla przypomnienia start mojego serwera, bez ceregieli, wyglądał następująco:

http.ListenAndServe(":8001", Router)

gorilla/handlers

Na ratunek, przyszła biblioteka gorilla/handlers. Jak nazwa wskazuje, jest to zbiór handlerów do pakietu net/http. Użycie jest bardzo proste i intuicyjne.

Instalujemy bibliotekę:

go get github.com/gorilla/handlers

Po imporcie i wpięciu w serwer już widać różnicę. Zmienił się status na 403 Forbidden.

CORS - golang - 403 Forbidden

Teraz wystarczy ustawić minimalne wymagane nagłówki i problem zażegnany:

CORS - golang - 200 OK

HTTP methods z Go i MongoDB – część 3 – PUT i DELETE

HTTP methods

W poprzednich dwóch częściach cyklu nauczyliśmy się tworzyć produkty, pobierać listę produktów oraz pojedynczy produkt za pomocą ID. Poniższy wpis zademonstruje, w jaki sposób możemy zaaktualizować produkt oraz jak go usunąć, czyli poznamy metody PUT i DELETE.

HTTP methods – PUT

Aktualizacja produktu

Do aktualizacji produktu wykorzystamy wiedzę, którą zdobyliśmy do tej pory – czyli pobieranie produktu po ID.

Na początek wykorzystamy pakiet gorilla/mux, aby dostać się parametrów zapytania. Następnie sprawdzamy czy wsród parametrów znajduje się ID. Jeżeli wszystko przebiegło poprawnie, to konwertujemy ID na ObjectIdHex.

W kolejnym kroku, podobnie jak przy metodzie POST, tworzymy nasz lokalny produkt, parsujemy i dekodujemy. Otwieramy połączenie z bazą danych i dzięki metodzie UpdateId, aktualizujemy nasz produkt przesyłając kolejno oid i product.

Na koniec standardowe ustawienie nagłówków: "Content-Type", "application/json", odpowiedź 200 - OK. Zamykamy sesję i zwracamy nasz zmodyfikowany produkt w formacie JSON.

Efekt pracy w POSTMANie:

Postman - PUT method- HTTP

HTTP methods – DELETE

Usuwanie produktu

Usuwanie produktów, na podstawie naszych doświadczeń, wydaje się teraz dziecinnie proste.

Metoda remove(), nie różni się niczym znaczącym od wcześniej wspomnianych metod. Całą magię wykonuje RemoveId(), gdzie jako parametr przekazujemy ObjectIdHex. Efekt naszej pracy na screenie poniżej:

Postman - DELETE method- HTTP

Podsumowanie

Powyższy wpis, to trzecia i ostatnia część cyklu HTTP methods. Praca nad tymi kilkoma endpointami dała mi wiele satysfakcji. Zdaję sobie sprawę z tego, że wymagają one poprawy. Poszedłem na duże uproszczenia, ale ucząc się języka Go oraz MongoDB, postawiłem sobie na razie za cel: minimalną, działającą funkcjonalność. To będzie dobry wstęp do czegoś większego.

HTTP methods z Go i MongoDB – część 2 – GET

HTTP methods

Dobrze zaplanowana praca, to podstawa. W poprzedniej części HTTP methods, nauczyliśmy się tworzyć produkty, za pomocą metody POST. W tym wpisie czas na pobieranie listy produktów oraz pojedynczego produktu po ID.

Dzięki tym trzem endpointom będziemy mogli skutecznie i efektywnie rozpocząć pracę nad front-endem naszej aplikacji.

HTTP methods – GET

Do pobierania elementów z bazy MongoDB użyjemy pakietów net/http, gorilla/mux oraz mgo.v2/bson. Do przetworzenia i wyświetlenia danych przydadzą się nam dodatkowo pakiety encoding/json oraz fmt.

Pobieranie listy produktów – getAll()

Zacznijmy od pobierania listy produktów. Metoda getAll(), którą za chwilę stworzymy, umożliwi nam wyświetlenie listy wszystkich produktów. Nie skupiam się na paginacji, filtrowaniu czy sortowaniu. Podobnie jak w poprzednim wpisie, na razie, interesuje mnie minimalna funkcjonalność.

Analogicznie, jak w poprzednim wpisie, na początku, tworzymy metodę getAll(), która jako parametry przyjmuje http.ResponseWriter oraz *http.Request. Po czym, na bazie struktury Products tworzymy lokalną zmienną o tej samej nazwie.

Całą “magię” załatwia za nas odpowiednie zapytanie do bazy danych: server.GetSession().DB("shopping-manager").C("products").Find(nil).All(&products)

Korzystamy ze stworzonego wcześniej lokalnego pakietu server i metody GetSession. Całość bazuje na pakiecie mgo.v2.  Po otwarciu sesji, wybraniu bazy danych oraz kolekcji, używamy metod Find i All, by wylistować wszystkie elementy z kolekcji.

Dodajemy jeszcze warunek, że jeżeli niczego nie znajdziemy, to endpoint odpowie nam statusem 404 - NOT FOUND. W przeciwnym wypadku standardowa odpowiedź czyli 200 - OK wraz z nagłówkiem "Content-Type", "application/json".

Na koniec zaprezentujmy wynik naszej pracy w formacie JSON, w czym pomoże nam metoda Marshal z pakietu encoding/json. Pamiętajmy o użyciu blank identifier.

Prezentacja odpowiedzi w Postmanie:

Postman - GET method- HTTP

Pobieranie produktu po ID – get()

Pobieranie produktu po ID, jest analogiczne jak powyższy przykład.

Potrzebujemy dodatkowo pobrać odpowiedni ID. Z pomocą przyjdzie nam, znana już paczka, gorilla/mux. Za pomocą metody Var, jesteśmy w stanie stworzyć obiekt params. Następnie zwracamy ObjectId w postaci hexa.

Przygotowana przez nas zmienna oid, pozwoli nam na przeszukanie kolekcji za jej pomocą. Zakładając, że ID w bazie są unikalne używamy metody Find, gdzie jako parametr przekazujemy oid, następnie wyciągamy znaleziony produkt.

Warto przy tej okazji pokazać jak zbudowany jest nasz endpoint: server.Router.HandleFunc("/product/{id}", get).Methods("GET").

Na koniec, standardowo, odpowiedź z Postmana:

Postman - GET by ID method- HTTP

Podsumowanie

Po pierwszych dwóch tygodniach pracy z językiem Go jestem bardzo zadowolony z jej efektów. Pisanie w tym języku jest bardzo szybkie i efektywne. W miarę poznawania kolejnych pakietów, odkrywając strukturę języka i poznając dobre praktyki mam wrażenie, że język ten został napisany specjalnie dla mnie. Tym nieskromnym stwierdzeniem zamykam, na tydzień, pracę nad backendem mojej konkursowej aplikacji Shopping Manager.