Skip to content

Instantly share code, notes, and snippets.

@pimbrouwers
Last active April 5, 2024 20:53
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save pimbrouwers/8f78e318ccfefff18f518a483997be29 to your computer and use it in GitHub Desktop.
Save pimbrouwers/8f78e318ccfefff18f518a483997be29 to your computer and use it in GitHub Desktop.
C# Parse Link Header
public class LinkHeader
{
public string FirstLink { get; set; }
public string PrevLink { get; set; }
public string NextLink { get; set; }
public string LastLink { get; set; }
public static LinkHeader LinksFromHeader(string linkHeaderStr)
{
LinkHeader linkHeader = null;
if (!string.IsNullOrWhiteSpace(linkHeaderStr))
{
string[] linkStrings = linkHeaderStr.Split(',');
if (linkStrings != null && linkStrings.Any())
{
linkHeader = new LinkHeader();
foreach (string linkString in linkStrings)
{
var relMatch = Regex.Match(linkString, "(?<=rel=\").+?(?=\")", RegexOptions.IgnoreCase);
var linkMatch = Regex.Match(linkString, "(?<=<).+?(?=>)", RegexOptions.IgnoreCase);
if (relMatch.Success && linkMatch.Success)
{
string rel = relMatch.Value.ToUpper();
string link = linkMatch.Value;
switch (rel)
{
case "FIRST":
linkHeader.FirstLink = link;
break;
case "PREV":
linkHeader.PrevLink = link;
break;
case "NEXT":
linkHeader.NextLink = link;
break;
case "LAST":
linkHeader.LastLink = link;
break;
}
}
}
}
}
return linkHeader;
}
}
@Knazys
Copy link

Knazys commented Jun 2, 2018

Thank You!

@caiolouro
Copy link

Thanks!

@iesen
Copy link

iesen commented Aug 11, 2020

thanks

@pimbrouwers
Copy link
Author

@Knazys, @caiolouro, @iesen -- most welcome :)

@tyronsea
Copy link

Awesome work, many thanks.

@TheAngryByrd
Copy link

Thanks!

Made an F# version:

module Http =
    type LinkHeader = {
        First : string option
        Last : string option
        Next : string option
        Previous : string option
    }
        with
            static member Empty =
                {
                    First = None
                    Last = None
                    Next = None
                    Previous = None
                }
    module LinkHeader =
        open System.Text.RegularExpressions
        let parse (linkHeader : string) =
            let linksStrings = linkHeader.Split(',')
            let linkHeader = LinkHeader.Empty
            let findLink (linkString : string) =
                let relMatch = Regex.Match(linkString, "(?<=rel=\").+?(?=\")", RegexOptions.IgnoreCase)
                let linkMatch = Regex.Match(linkString, "(?<=<).+?(?=>)", RegexOptions.IgnoreCase)
                if relMatch.Success && linkMatch.Success then
                    Some (relMatch.Value.ToUpper(), linkMatch.Value)
                else
                    None
            (linkHeader,linksStrings)
            ||> Array.fold (fun lh ls ->
                match findLink ls with
                | Some("FIRST", l) ->
                    { lh with First = Option.ofObj l}
                | Some("PREV", l) ->
                    { lh with Previous = Option.ofObj l}
                | Some("NEXT", l) ->
                    { lh with Next = Option.ofObj l}
                | Some("LAST", l) ->
                    { lh with Last = Option.ofObj l}
                | _ ->
                    lh
            )

@pimbrouwers
Copy link
Author

Yasssss @TheAngryByrd!

@Digitalroot
Copy link

Digitalroot commented Nov 5, 2020

I added the following ctor.

    public static LinkHeader LinksFromHeader(HttpResponseMessage httpResponseMessage)
    {
      if (httpResponseMessage.Headers.Contains("Link"))
      {
        return CreateInstance(httpResponseMessage.Headers.GetValues("Link").FirstOrDefault());
      }

      return null;
    }

I am using it to loop though and build a list of GitHub Pull Requests.

      var jsonList = new List<string>();
      var url = $"{repo.Url}/pulls?state=closed&base=develop";
      do
      {
        HttpResponseMessage response = httpClient.GetAsync(url).Result;

        var linkHeader = LinkHeader.LinksFromHeader(response);

        using (StreamReader stream = new StreamReader(response.Content.ReadAsStreamAsync().Result))
        {
          jsonList.Add(stream.ReadToEnd());
        }

        url = linkHeader.NextLink;

      } while (url != null);

      return jsonList;

Full Source: https://gist.github.com/Digitalroot/e9ca35596664fccd13494cf2da975aa2

@golden-aries
Copy link

Many thanks Pim! It Works!

@dbruning
Copy link

dbruning commented Dec 26, 2023

Note that this breaks if the URL's themselves have commas in them. A more robust solution is here: https://stackoverflow.com/a/72034960

@DavidKlempfner
Copy link

Works great, thanks!

@AndrewTran03
Copy link

Is there a JS/TS equivalent to this? If not, could someone please help me with writing this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment