Czy ktoś programował wyciąganie danych z Gitlaba. Szukam informacji na temat tego jak zacząć, chciałbym zrobić kilka zestawień informacji z repozytorium Gitalaba do pliku CSV ale nie wiem jak to ugryźć może ktoś może coś podpowiedzieć od czego zacząć. Gdzie znajdę informację jak podpiąć się pod api
Proste restowe api. Z czym masz problem?
Jeszcze nie problem tylko jeszcze tego nie robiłem i nie wiem jak zacząć. Potrzebuje zrobić np. zestawienie wszystkich tagów z wszystkich projektów jakie mam w Gitlabie. Szukam jakiegoś przykładu na którym mógłbym zacząć a potem za pomocą zapytań kombinować co konkretnie chce osiągnąć
Mam dobre wrażenia z taką biblioteką kliencką RestSharp.
Ale jak nic nigdy takiego nie ćwiczyłeś, to jest droga przed tobą
Spróbowałem coś zrobić z Microsoft.AspNet.WebApi.Client ale zawiesiłem się na autoryzacji za pomocą tokenu. Jeśli robię to tak jak zamieściłem dostaję response 200. Jeśli jednak próbuję dodać mój token za pomocą client.DefaultRequestHeaders.Add("access-token", accessToken); to otrzymuję zwrotkę 404. Ktoś coś podpowie na szybko?
static async Task RunAsync()
{
using (var client = new HttpClient())
{
string accessToken = "mój_token";
client.BaseAddress = new Uri("https://lokalny_gitlab/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//client.DefaultRequestHeaders.Add("access-token", accessToken);
Console.WriteLine("GET");
HttpResponseMessage response = await client.GetAsync("/api/v4/projects/515/?private_token=mój_token");
Console.WriteLine(response);
Console.ReadLine();
//if (response.IsSuccessStatusCode)
}
}
}
}
aksimoN napisał(a):
Spróbowałem coś zrobić z Microsoft.AspNet.WebApi.Client ale zawiesiłem się na autoryzacji za pomocą tokenu. Jeśli robię to tak jak zamieściłem dostaję response 200. Jeśli jednak próbuję dodać mój token za pomocą client.DefaultRequestHeaders.Add("access-token", accessToken); to otrzymuję zwrotkę 404. Ktoś coś podpowie na szybko?
Ok,
Zerkając pobieżnie po dokumentacji API Gitlaba z tego co widzę, to używają access_token
zamiast access-token
,
Następnie - dlaczego access_token
w headerze jeżeli w przykładach podają go w URL jako
GET https://gitlab.example.com/api/v4/user?access_token=OAUTH-TOKEN
a jeżeli chcesz używać headera to powinieneś użyć przeznaczonego do tego / używanego przez nich headera, czyli jak zgaduje
Key: Authorization
Value: Bearer _token_
curl --header "Authorization: Bearer OAUTH-TOKEN" "https://gitlab.example.com/api/v4/user"
Stworzyłem klasę Tag:
public class Tag
{
public string id { get; set; }
public string tag_name { get; set; }
public string reference { get; set; }
public string message { get; set; }
public string release_description { get; set; }
}
I teraz odpytuję GitLaba i chciałbym zdeserializować „content responsa” (jeśli dobrze rozumiem co muszę zrobić) do listy Tagów.
Czyli jeśli otrzymam pozytywną odpowiedź, a dostaję 200 czyli zapytanie działa, chciałbym odpowiedź z API wrzucić do listy
class Program
{
static void Main(string[] args)
{
RunAsync().Wait();
}
static async Task RunAsync()
{
using (var client = new HttpClient())
{
string apiAccessToken = "?private_token=mój_token";
string apiString = "/api/v4/";
string apiReq = "projects/515/repository/tags";
string apiPath = apiString+apiReq+apiAccessToken;
client.BaseAddress = new Uri("mojeuri");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json
HttpResponseMessage response = await client.GetAsync(apiPath);
string content = await client.GetStringAsync(apiPath);
//Console.WriteLine(content);
List<Tag> tagi = new List<Tag>();
if (response.IsSuccessStatusCode)
{
tagi = JsonConvert.DeserializeObject<List<Tag>>(content);
}
Console.ReadLine();
}
}
}```
Lista tagi wygląda tak:
![screenshot-20201022145109.png](https://4programmers.net/uploads/attachment/5f/5f91803df29a9.png)
WeiXiao napisał(a):
a co jest w content?
zserializowane dane?
string content = await client.GetStringAsync(apiPath);
btw: nie wolisz użyć
RestSharp
a?
Może i bym wolał ale znalazłem jakiś przykład zrobiony w taki sposób i próbuje analogicznie poprzerabiać to do swoich potrzeb ale wychodzi na to że to trochę coś innego.
Na razie działam po omacku
Z tego co widzę, to masz lekki rozjazd.
Twój Json reprezentuje inne dane niż List<Tag>
, już na pierwszy rzut oka widać że nie ma name
i obstawiam że coś tutaj powoduje problem (niekoniecznie akurat name
).
Weź skopiuj ten JSON i użyj np. w Visual Studio opcji Paste JSON as Classes
w jakimś pliku .cs
, to ci wygeneruje odpowiednie klasy, a później powinno wystarczyć coś typu DeserializeObject<RootObject>(content)
, gdzie RootObject
jest tą wygenerowaną klasą "najwyższego poziomu".
Twój Json reprezentuje inne dane niż List<Tag>, już na pierwszy rzut oka widać że nie ma name i obstawiam że coś tutaj powoduje problem (niekoniecznie akurat name).
Jest name
:
Ale rzeczywiście coś nie zgrywa z tą klasą.
Skopiowałem zawartość odpowiedzi z RESTer i paste special do nowej klasy Tags:
class Tags
{
public class Rootobject
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string name { get; set; }
public string message { get; set; }
public string target { get; set; }
public Commit commit { get; set; }
public Release release { get; set; }
public bool _protected { get; set; }
}
public class Commit
{
public string id { get; set; }
public string short_id { get; set; }
public DateTime created_at { get; set; }
public string[] parent_ids { get; set; }
public string title { get; set; }
public string message { get; set; }
public string author_name { get; set; }
public string author_email { get; set; }
public DateTime authored_date { get; set; }
public string committer_name { get; set; }
public string committer_email { get; set; }
public DateTime committed_date { get; set; }
public string web_url { get; set; }
}
public class Release
{
public string tag_name { get; set; }
public string description { get; set; }
}
}
ale w liscie tagi nadal siedzi to samo, może tu coś robię źle?
tagi = JsonConvert.DeserializeObject<List<Tags>>(content);
a co ja pisałem wcześniej o root object? :(
WeiXiao napisał(a):
a co ja pisałem wcześniej o root object? :(
Nie wiem czy nadążam, poprawiłem klasę, zamiast Rootobject mam teraz Tags:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RestApiToGit
{
public class Tags
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string name { get; set; }
public string message { get; set; }
public string target { get; set; }
public Commit commit { get; set; }
public Release release { get; set; }
public bool _protected { get; set; }
}
public class Commit
{
public string id { get; set; }
public string short_id { get; set; }
public DateTime created_at { get; set; }
public string[] parent_ids { get; set; }
public string title { get; set; }
public string message { get; set; }
public string author_name { get; set; }
public string author_email { get; set; }
public DateTime authored_date { get; set; }
public string committer_name { get; set; }
public string committer_email { get; set; }
public DateTime committed_date { get; set; }
public string web_url { get; set; }
}
public class Release
{
public string tag_name { get; set; }
public string description { get; set; }
}
}
robię tak:
HttpResponseMessage response = await client.GetAsync(apiPath);
var content = await client.GetStringAsync(apiPath);
List<Tags> tagi = new List<Tags>();
tagi = JsonConvert.DeserializeObject<List<Tags>>(content);
i niestety mam Property1 null:
Twój json reprezentuje obiekt który w sobie ma tablicę, a Ty próbujesz zamienić ten obiekt (który ma w sobie tablicę) na listę. poprawione niżej
Zamiast List<Tags>
przy Deserialize, to podaj nazwę tej klasy, która ma w sobie te Class1[] Property1
, czyli po ostatnich zmianach: Tags
Generalnie tak jak Ci Visual Studio wygenerowało te klasy, to wystarczyło zrobić Deserialize na Rootobject
- ten, który miał w sobie tablicę tych twoich pożądanych obiektów.
WeiXiao napisał(a):
Twój json reprezentuje obiekt który w sobie ma tablicę, a Ty próbujesz zamienić ten obiekt (który ma w sobie tablicę) na listę.
ZamiastList<Tags>
przy Deserialize, to podaj nazwę tej klasy, która ma w sobie teClass1[] Property1
, czyli po ostatnich zmianach:Tags
Generalnie tak jak Ci Visual Studio wygenerowało te klasy, to wystarczyło zrobić Deserialize naRootobject
- ten, który miał w sobie tablicę tych twoich pożądanych obiektów.
No to teraz wywala się na tej lini:
tagi = JsonConvert.DeserializeObject<Tags>(content);
I leci do góry do linii:
RunAsync().Wait();
@aksimoN
Podrzuć tu fragment / całego tego jsona
WeiXiao napisał(a):
Podrzuć tu fragment / całego tego jsona
{
"name": "1.01.004C",
"message": "",
"target": "9a8ab4012ad7e1c258e619795c985cbd7ace022f",
"commit": {
"id": "9a8ab4012ad7e1c258e619795c985cbd7ace022f",
"short_id": "9a8ab401",
"created_at": "2020-10-21T13:52:13.000+02:00",
"parent_ids": [
"1f8b35e1cfb78f0d96bbcdc703bb6ff860596adf",
"4117d1dd6e1f1b8bcbdc1b20caf209b8ca3ff5fa"
],
"title": "AA 1.01.004C",
"message": "AA 1.01.004C",
"author_name": "autor.autor",
"author_email": "[email protected]",
"authored_date": "2020-10-21T13:52:13.000+02:00",
"committer_name": "autor.autor",
"committer_email": "[email protected]",
"committed_date": "2020-10-21T13:52:13.000+02:00",
"web_url": "https://lokalny_git/AA/-/commit/9a8ab4012ad7e1c258e619795c985cbd7ace022f"
},
"release": {
"tag_name": "1.01.004C",
"description": "poprawki\\[nowa wersja]"
},
"protected": false
}
Ok, przerobiłem twojego jsona na array tych obiektów i faktycznie mój błąd
var test = JsonConvert.DeserializeObject<List<Class1>>(json);
public class Class1
{
public string name { get; set; }
public string message { get; set; }
public string target { get; set; }
public Commit commit { get; set; }
public Release release { get; set; }
public bool _protected { get; set; }
}
public class Commit
{
public string id { get; set; }
public string short_id { get; set; }
public DateTime created_at { get; set; }
public string[] parent_ids { get; set; }
public string title { get; set; }
public string message { get; set; }
public string author_name { get; set; }
public string author_email { get; set; }
public DateTime authored_date { get; set; }
public string committer_name { get; set; }
public string committer_email { get; set; }
public DateTime committed_date { get; set; }
public string web_url { get; set; }
}
public class Release
{
public string tag_name { get; set; }
public string description { get; set; }
}
To co pisałem
Twój json reprezentuje obiekt który w sobie ma tablicę, a Ty próbujesz zamienić ten obiekt (który ma w sobie tablicę) na listę.
Miałoby sens gdyby to wyglądało tak
{
"Dane":
[
{
},
{
}
]
}
a nie
[{},{}]
WeiXiao napisał(a):
U mnie działa
pokaż jak wrzuciłeś tego JSONa do json
json: https://pastebin.com/raw/rF6iJxez
var json = File.ReadAllText("test.txt");
WeiXiao napisał(a):
json: https://pastebin.com/raw/rF6iJxez
var json = File.ReadAllText("test.txt");
Poszło mi z pliku dla pojedynczego i poszło mi dla całego jsona do listy:
HttpResponseMessage response = await client.GetAsync(apiPath);
var content = await client.GetStringAsync(apiPath);
List<Tags> tagi = new List<Tags>();
tagi = JsonConvert.DeserializeObject<List<Tags>>(content);
Console.WriteLine(tagi[0].name.ToString());
Wychodzi na to że głównym problemem była źle zbudowana klasa Tags?
Sprawdziłem na twojej poprzedniej implementacji klasy
public string id { get; set; }
public string tag_name { get; set; }
public string reference { get; set; }
public string message { get; set; }
public string release_description { get; set; }
i też mi nie działa, więc najwidoczniej tak.
No to ostatnie już pytanko, chcę sobie teraz na tym budować metody które zwracają konkretne obiekty.
Zbudowałem metodę która wypisuje tag_name i description, i to działa:
async void GetProjectTags(string apiReq)
{
string apiPath = apiString + apiReq + apiAccessToken;
HttpResponseMessage response = await client.GetAsync(apiPath);
var content = await client.GetStringAsync(apiPath);
List<Tags> tagi = new List<Tags>();
tagi = JsonConvert.DeserializeObject<List<Tags>>(content);
foreach (var item in tagi)
{
Console.WriteLine(item.release.tag_name);
Console.WriteLine(item.release.description);
}
}
Chcę ją przerobić tak żeby zwracała List<Tags>, coś w tym stylu:
async List<Tags> GetProjectTags(string apiReq)
{
string apiPath = apiString + apiReq + apiAccessToken;
HttpResponseMessage response = await client.GetAsync(apiPath);
var content = await client.GetStringAsync(apiPath);
List<Tags> tagi = new List<Tags>();
tagi = JsonConvert.DeserializeObject<List<Tags>>(content);
return tagi;
}
problem w tym że:
The return of async method must be void, Task, Task<T>....
List<Tags
-> Task<List<Tags>>
Generalnie async void
jest czymś, czego się nie zaleca stosować poza pewnym wyjątkiem, a zamiast tego stosować async Task
Async/Await - Best Practices in Asynchronous Programming @ March 2013