DEV Community

Nick Weymiens
Nick Weymiens

Posted on

First Project: A Client to an API

Hello,

Recently I decided to pick up coding to make a dream project I had in mind for a very long time. It is a rather big project so at the moment it is practically impossible to deliver the things I want to deliver with the skills I currently posses. Thus, the best thing to do is to chop up the huge project into smaller more manageable pieces that I can reasonably manage while learning to code at the same time.

KrDictClient

The project is centered around my passion for Korea and its language thus having access to a great dictionary is simply a must for certain things I want to do. Luckily, the National Institute of Korean Language offers an (old) open API that would make that possible.

Because its documentation is rather questionable and 100% in Korean, I decided my first project would be client library for .NET called KrDictClient. The project would be naturally open-source (git repository can be found here), because I do want to make the api accessible to more people so people can do more things with Korean.

State of the Project

Currently, this one-man project by a beginner is progressing, though I am near certain a lot of improvements can be made and I would not say it is finished by a long shot. Exception handling needs to be added still at the bare minimum!

Nonetheless, it is at least functional as intended it seems as long as whoever uses it doesn't cause the API to return an error. There are a few parts I am rather proud of since I do think this makes consuming the API via this library a bit easier. I would like to highlight that here.

Generic Interface

The backbone is bases on 3 important classes SearchKrDictClient, DetailKrDictClient and IKrDictClient.

These classes do the actual client work, they send requests, receive it and ask other mapper clases to turn the xml responses into objects.

However, the main goal of these classes is to make writing the requests a lot easier. The API expects a lot of parameters, which makes the request uri very difficult to write and read. However, this tedious work is reduced severely by these classes, as they only require the your API Key and the query to function. You can, however, customize the request via the properties, but you needn't do that since default values will be assigned.

When making the request the client will just call a private FormatRequest method to turn the parameters into a functional string like this:

public override string FormatRequest()
{
    if (TransLang is not null)
    {
        // Return example: /search?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&q=나&num=10&sort=popular&part=word&translated=y&trans_lang=1
        return string.Format("https://krdict.korean.go.kr/api/search?key={0}&q={1}&num={2}&sort={3}&part={4}&translated=y&trans_lang={5}",
            _apiKey,
            Query,
            Amount,
            Sort == Sort.Dictionary ? "dict" : "popular",
                    Parser.GetSectionString(Section),
            (int)TransLang);
     }    
     else
     {
         // Return example: /search?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&q=나&num=10&sort=popular&part=word
         return string.Format("https://krdict.korean.go.kr/api/search?key={0}&q={1}&num={2}&sort={3}&part={4}",
             _apiKey,
             Query,
             Amount,
             Sort == Sort.Dictionary ? "dict" : "popular",
             Parser.GetSectionString(Section));
     }
}
Enter fullscreen mode Exit fullscreen mode

This library also has a lot of enums, these enums are created whenever the API utilizes parameters of response values with a limited amount of options but the documentation is in Korean so these options might be illegible for some. To solve that issue these enums came into being. Plus I'd imagine enums are a lot easier to handle than having these things as strings.

public enum Level
{
    None,
    Beginner,
    Intermediate,
    Advanced
}
Enter fullscreen mode Exit fullscreen mode

The Area of improvement

However, as mentioned there are parts that work, but I feel could use a lot of improvement. The mapping of data to C# object is currently handled by using XDocumen. It reads the xml document and map the data in that way, but I am rather unsure wether they way I go about it is any good.

It happens like this currently:

public SearchData MapResponse(XDocument response)
{
    SearchData searchData = new SearchData();
    searchData.QueryResults = new List<EntryData>();

    foreach (XElement item in response.Descendants("item"))
    {
        searchData.QueryResults.Add(new()
        {
            Term = item.Element("word").Value,
            Origin = item.Element("origin") is not null ? item.Element("origin").Value : null,
            Pronunciation = item.Element("pronunciation") is not null ? item.Element("pronunciation").Value : null,
            Level = item.Element("word_grade") is not null ? Parser.ParseLevel(item.Element("word_grade").Value) : Level.None,
            PartOfSpeech = item.Element("pos").Value,
            AttributionUrl = item.Element("link").Value,
            DetailSearchQuery = new StringBuilder().Append(item.Element("word").Value).Append(item.Element("sup_no").Value).ToString(),
            Senses = ParseSenses(item.Descendants("sense"))
                });
            }
Enter fullscreen mode Exit fullscreen mode

I initially tried it with xml deserialization, but no matter that I tried I always get the Exception that the root element was missing and I never figured out what was causing it so I went to this route. It is a shame, because I think deserialization would make the code a lot more readable (it is hard to read if you are not intimate with the API).

If anyone could share some ideas on perhaps improving my code I would love to know since I am still in the middle of learning and .NET has lot that needs to be learned. Do not hesitate to offer tips and tricks and links to things I ought to see.

Top comments (0)