Git Product home page Git Product logo

github-graphql's People

Contributors

chshersh avatar dependabot[bot] avatar vrom911 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

github-graphql's Issues

Support querying Milestone by number and add helper query to get milestone by number

Currently we don't have a way to query Milestone by number:

query { 
  repository(owner: "kowainik", name: "hit-on") {
    milestone(number: 1) {
      id
    }
  }
}

With the response:

{
  "data": {
    "repository": {
      "milestone": {
        "id": "MDk6TWlsZXN0b25lNDQ4MDI1Mg=="
      }
    }
  }
}

For this, we need to add a milestone connection to Repository. Similar to Issue/Issues we need to have Milestone/Milestones:

  • repositoryFieldToAst :: RepositoryField -> QueryNode
    repositoryFieldToAst = \case
    RepositoryId -> nameNode NodeId
    RepositoryIssue issueField -> issueToAst issueField
    RepositoryIssues issuesField -> issuesToAst issuesField
    RepositoryMilestones milestonesField -> milestonesToAst milestonesField
    RepositoryPullRequests pullRequestsField -> pullRequestsToAst pullRequestsField

Additionally, it would be nice to have a helper function to query MilestoneId similar to querying RepositoryId:

  • {- | Helper function to fetch 'RepositoryId'. It is often needed as
    argument to other queries.
    This function parses resulting JSON of the following shape:
    @
    {
    "data": {
    "repository": {
    "id": "MDEwOlJlcG9zaXRvcnkyOTA1MDA2MzI="
    }
    }
    }
    @
    -}
    queryRepositoryId
    :: GitHubToken -- ^ Bearer token
    -> Text -- ^ Owner
    -> Text -- ^ Repository name
    -> IO RepositoryId
    queryRepositoryId token owner repoName =
    fmap unRepositoryData
    $ queryGitHub @(RepositoryData RepositoryId) token
    $ GH.repositoryToAst repositoryIdQuery
    where
    repositoryIdQuery :: GH.Repository
    repositoryIdQuery = GH.repository
    ( GH.defRepositoryArgs
    & set GH.ownerL owner
    & set GH.nameL repoName
    )
    $ one GH.RepositoryId

And add tests for this function (e.g. using the example in this issue).

Improve error-reporting mechanism

Currently, when something is wrong, it's hard to understand why. I propose to add a custom data type and return it as an error.

The data type will contain:

  • Rendered query
  • Returned JSON
  • Parsing error message
  • Details from the query (see explanation below)

When you provide an invalid query like this:

query {
  repository(owner: "kowainik", "github-graphql") {
    issue(number: 5) {
      bodies
    }
  }
}

GitHub API returns the following message:

{
  "errors": [
    {
      "message": "Parse error on \"github-graphql\" (STRING) at [2, 33]",
      "locations": [
        {
          "line": 2,
          "column": 33
        }
      ]
    }
  ]
}

Ideally, this shouldn't happen in users' code (because we provide type-safe API), but this still can happen due to errors in our library, so it's good to provide more info here.

Render GraphQL AST pretty

Example:

query { 
  repository(owner: "kowainik", name: "github-graphql") {
    issues(last: 3) {
        nodes {
          title
          author{
            login
          }
        }  
    }
  }
}

Split AST types into different modules

GitHub GraphQL API is huge! And it won't be ideal to keep all types in the same single module. So let's refactor a bit and move them into separate modules.

Implement endpoint that will take Query and call the real API

For now, it can return ByteString if we want to avoid dependencies on aeson and let users decide what library to use aeson or microaeson or something else.

The function should take token and a query. An example curl command looks like this:

$ curl -H "Authorization: bearer token" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
" https://api.github.com/graphql

I think, we can use the httpLbs function to call server and http-client-tls library for creating TLS manager:

It's a bit heavy on the dependencies side but that's the only Haskell-only solution... Maybe we can just use curl? πŸ€”

Custom error messages for types

Similar to the Repository type. Messages probably will have the same structure, so maybe it makes sense to have a helper type family that takes several arguments and builds the message from them.

The following types currently lack custom error messages:

  • RepositoryArgs
  • IssuesArgs
  • PullRequestsArgs
  • CreateIssueInput
  • IssueOrder
  • LabelsArgs
  • AssigneesArgs

Implement 'Mutation'

According to GraphQL, if we want to create news issues, we need to implement the Mutation type similar to Query...

Add `OrderNumber` constructor to `OrderField`

So we can fetch the latest milestone using the following query:

query { 
  repository(owner: "kowainik", name: "hit-on") {
    milestones(last: 1, orderBy: {field: NUMBER, direction: DESC}) {
      nodes {
        title
      }
    }
  }
}

Test that calling API works

I realized, that with current types it's a bit hard to test, and will require a bit of work...

I propose to use the following query to write the test, because the output of this query won't change with time:

query { 
  repository(owner: "kowainik", name: "hit-on") {
    issues(last: 2, states: [CLOSED], orderBy: {field: CREATED_AT, direction: DESC}) {
        nodes {
          title
          author{
            login
          }
        }  
    }
  }
}

The output looks like this:

{
  "data": {
    "repository": {
      "issues": {
        "nodes": [
          {
            "title": "Implement \"git-new\"-like command: `hit hop`",
            "author": {
              "login": "chshersh"
            }
          },
          {
            "title": "Implement basic CLI interface",
            "author": {
              "login": "vrom911"
            }
          }
        ]
      }
    }
  }
}

For this we need to do the following:

  • Write a function to extract GITHUB_TOKEN
  • Support records as params {}
  • Add OrderDirection type with ASC and DESC constructors
  • Write the type and a JSON parser
  • Write the test

Minimal requirements to support `hit-on`

The first project to use github-graphql is going to be hit-on. And for this to happen, we need to support the following types and operations:

  • Query
    • Issue return fields
      • Issue number
      • Title
      • Author
      • Assignees
      • Labels
      • URL
      • Description
      • Closed
    • Milestone return fields
      • Id
      • Number (for sorting and taking the latest)
      • Name
      • Number of open issues
      • Number of closed issues
    • Get all issues and filter by the following fields
      • Owner
      • Repository
      • Open state
    • Get a single issue by number
    • Get all pull requests
      • Owner
      • Repo
      • Option (only single PR per branch is allowed): let headPrMod = optionsHead $ untagName owner <> ":" <> curBranch
    • RepositoryId (needed for many mutation queries)
      • Owner
      • Name
  • Mutation
    • Create new issue
      • RepositoryId
      • Title
      • Optional milestone
    • Assign issue
      • By number/id
      • Author

Since GitHub GraphQL API provides more flexibility than the REST API, we probably can improve some of our queries in hit-on by fetching less or by filtering directly in the query. So, other possible suggestions and improvements are welcome πŸ™‚

More modular structure

Current structure of modules is a bit messy:

GitHub
  GitHub.Author
  GitHub.Connection
  GitHub.GraphQL
  GitHub.Id
  GitHub.Issue
  GitHub.Label
  GitHub.Lens
  GitHub.Milestone
  GitHub.Order
  GitHub.PullRequests
  GitHub.Render
  GitHub.Query
  GitHub.Repository
  GitHub.RequiredField
  GitHub.Title
  GitHub.User

Current problem is that we have fields for different types (title of issue, login of user, etc.) and we also have different connections with input parameters (issue by state, pullrequests, etc.). Some connections can be polymorphic, so to abstract further, it's better to separate types.

I propose a new structure with clearer boundaries (and probably avoiding recursive dependencies).

I will write in a shorter syntax for clarity. Mostly duplicates the GitHub API structure:

GitHub
  Types
    Connection
    Issue
    Milestone
    PullRequest
    User
    Id
  Connections
    Labels
    Issue  -- issue by number
    Issues  -- list of issues
    PullRequests
    Milestones
  Interface
    Actor  -- has author name
  Enums
    IssueState
    PullRequestState
    IssueOrder
  Queries
    Repository
    Viewer
  Mutations
    CreateIssue
    AddAssigneesToAssignable
  GraphQL
    Query
    Mutation
    Render
  API  -- calling remote API, better name needed
    Common
    Query
    Mutation
  Abstraction  -- local abstractions for better UX and UI, better name needed
    Lens
    Author  -- HasAuthor typeclass and instances
    Title  -- HasTitle typeclass and instances
    RequiredField

With this structure, it's clear what to add and where:

  1. All new types go to GitHub.Types.
  2. All new connections for those types use types and go to GitHub.Connection
  3. New read-only queries and mutations go to the corresponding sections.
  4. Functions to call GitHub API are in the GitHub.API module.
  5. Our local helpers in GitHub.Abstraction

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.