Graph API client writen in Rust

Related tags

Graphics graph-rs
Overview

graph-rs

Build Build status

Now available on stable Rust at crates.io

graph-rs-sdk = "0.1.0"

0.1.0 and above use stable Rust. Anything before 0.1.0 uses nightly Rust.

Microsoft Graph API Client in Rust

Installation and basic usage can be found below and there are extensive examples in the example's directory included in the project on GitHub.

What Api's are available

The Api's available are generated from OpenApi configs that are stored in Microsoft's msgraph-metadata repository for the Graph Api. There may be some requests and/or Api's not yet included in this project that are in the OpenApi config but in general most of them are implemented.

Feature requests or Bug reports.

For both feature requests and bug reports please file an issue on GitHub and a response or fix will be given as soon as possible.

Use

The client supports both blocking and async requests.

Blocking Client

To use the blocking client

use graph_rs_sdk::prelude::*;

fn main() {
  let client =  Graph::new("ACCESS_TOKEN");
}

Async Client

To use the async client

use graph_rs_sdk::prelude::*;

fn main() {
  let client = Graph::new_async("ACCESS_TOKEN");
}

The send method and Graph types

The send() method is the main method for sending a request. The return value will be wrapped in a response object, GraphResponse<T> and the body will be a serde_json::Value. If the response is a 204 no content and there is no body then the response body returned will just be a serde_json::Value with an empty string.

use graph_rs_sdk::prelude::*;

let client =  Graph::new("ACCESS_TOKEN");

// Returns GraphResponse<serde_json::Value>
let response = client.v1()
    .me()
    .drive()
    .get_drive()
    .send()
    .unwrap();

For async requests use the await keyword.

use graph_rs_sdk::prelude::*;

let client =  Graph::new_async("ACCESS_TOKEN");

// Returns GraphResponse<serde_json::Value>
let response = client.v1()
    .me()
    .drive()
    .get_drive()
    .send()
    .await
    .unwrap();
        
println!("{:#?}", response);  

// Get the body of the response
println!("{:#?}", response.body());
Custom Types

The json() method can be used to convert the response body to your own types. These types must implement serde::Deserialize.

use graph_rs_sdk::prelude::*;
        
let client = Graph::new("ACCESS_TOKEN");
        
#[derive(Debug, Serialize, Deserialize)]
pub struct DriveItem {
    id: Option<String>,
    name: Option<String>,
    // ... Any other fields
}
        
let response: DriveItem = client.v1()
    .me()
    .drive()
    .get_items("ITEM_ID")
    .json()?;
        
println!("{:#?}", response);   

OneDrive

Make requests to drive using a drive id or through specific drives for me, sites, users, and groups.

use graph_rs_sdk::prelude::*;
    
let client = Graph::new("ACCESS_TOKEN");

// Some requests don't require an id.
let response = client.v1()
    .drives()
    .get_drive();

// Using a drive id.
let response = client.v1()
    .drive("DRIVE-ID")
    .get_items("ITEM_ID")
    .send()?;

// Using me.
let response = client.v1()
    .me()
    .drive()
    .get_items("ITEM_ID")
    .send()?;
    
println!("{:#?}", response);

// Using users.
let response = client.v1()
    .users("USER_ID")
    .drive()
    .get_items("ITEM_ID")
    .send()?;

println!("{:#?}", response);

// Using sites.
let response = client.v1()
    .sites("SITE-ID")
    .drive()
    .get_items("ITEM_ID")
    .send()?;

println!("{:#?}", response);

Create a folder.

let folder: HashMap<String, serde_json::Value> = HashMap::new();

let response = client.v1()
    .me()
    .drive()
    .create_folder(
        "PARENT_FOLDER_ID",
         &serde_json::json!({
            "name": "docs",
            "folder": folder,
            "@microsoft.graph.conflictBehavior": "fail"
         }),
    )
    .send()?;
        
println!("{:#?}", response);

Path based addressing for drive.

// Pass the path location of the item staring from the OneDrive root folder.
// Start the path with :/ and end with :
    
let response = client.v1()
    .me()
    .drive()
    .get_items(":/documents/document.docx:")
    .send()?;
        
println!("{:#?}", response.body());

Mail

use graph_rs_sdk::prelude::*;
        
let client = Graph::new("ACCESS_TOKEN");
        
// List messages for a user.
let response = client.v1()
    .user("USER-ID")
    .messages()
    .list_messages()
    .send()?;

// List messages using me.
let response = client.v1()
    .me()
    .messages()
    .list_messages()
    .send()?;
             
// Create a message
let response = client.v1()
    .user("USER_ID")
    .messages()
    .create_messages(&serde_json::json!({
        "subject":"Did you see last night's game?",
        "importance":"Low",
        "body":{
            "contentType":"HTML",
                "content":"They were <b>awesome</b>!"
            },
        "toRecipients":[{
            "emailAddress":{
                "address":"[email protected]"
            }
        }]
    }))
    .send()?;
        
println!("{:#?}", response.body()); // => Message

// Send mail.
let response = client.v1()
    .user("USER-ID")
    .send_mail(&serde_json::json!({
        "message": {
            "subject": "Meet for lunch?",
            "body": {
                "contentType": "Text",
                "content": "The new cafeteria is open."
            },
            "toRecipients": [
                {
                    "emailAddress": {
                        "address": "[email protected]"
                    }
                }
            ],
            "ccRecipients": [
                {
                    "emailAddress": {
                        "address": "[email protected]"
                    }
                }
            ]
        },
        "saveToSentItems": "false"
        }))
    .send()?;
                                       
println!("{:#?}", response);

Mail folders

// Create a mail folder.
let response = client.v1()
    .user("USER-ID")
    .mail_folders()
    .create_mail_folders(&serde_json::json!({
        "displayName": "Clutter"
    }))
    .send()?;

// List messages in a mail folder.
let response = client.v1()
    .me()
    .mail_folder("drafts")
    .messages()
    .list_messages()
    .send()?;

// Create messages in a mail folder.
let response = client.v1()
    .user("USER-ID")
    .mail_folder("drafts")
    .messages()
    .create_messages(&serde_json::json!({
        "subject":"Did you see last night's game?",
        "importance":"Low",
        "body":{
            "contentType":"HTML",
                "content":"They were <b>awesome</b>!"
            },
        "toRecipients":[{
            "emailAddress":{
                "address":"[email protected]"
            }
        }]
    }))
    .send()?;

Use your own struct. Anything that implements serde::Serialize can be used for things like creating messages for mail or creating a folder for OneDrive.

 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Message {
    subject: String,
    importance: String,
    body: HashMap<String, String>,
    #[serde(rename = "toRecipients")]
    to_recipients: Vec<ToRecipient>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
struct ToRecipient {
    #[serde(rename = "emailAddress")]
    email_address: EmailAddress,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
    struct EmailAddress {
        address: String,
    }

let mut body = HashMap::new();
body.insert("contentType".to_string(), "HTML".to_string());
body.insert("content".to_string(), "They were <b>awesome</b>!".to_string());
        
let message = Message {
    subject: "Did you see last night's game?".into(),
    importance: "Low".into(),
    body,
    to_recipients: vec![
        ToRecipient {
            email_address: EmailAddress {
                address : "[email protected]".into()        
            }                
        }
    ]
}
        
// Create a message
let response = client.v1()
    .me()
    .messages()
    .create_messages(&message)
    .send()?;
            
println!(":#?", response);

OData Queries

use graph_rs_sdk::prelude::*;
            
let client = Graph::new("ACCESS_TOKEN");
    
// Get all files in the root of the drive
// and select only specific properties.
let response = client.v1()
    .me()
    .drive()
    .get_drive()
    .select(&["id", "name"])
    .send()?;
    
println!("{:#?}", response.body());

Batch Requests

Batch requests use a mpsc::channel and return the receiver for responses.

use graph_rs_sdk::prelude::*;
use std::error::Error;

static USER_ID: &str = "USER_ID";

let client = Graph::new("ACCESS_TOKEN");

let json = serde_json::json!({
    "requests": [
        {
            "id": "1",
            "method": "GET",
            "url": format!("/users/{}/drive", USER_ID)
        },
        {
            "id": "2",
            "method": "GET",
            "url": format!("/users/{}/drive/root", USER_ID)
        },
        {
            "id": "3",
            "method": "GET",
            "url": format!("/users/{}/drive/recent", USER_ID)
        },
        {
            "id": "4",
            "method": "GET",
            "url": format!("/users/{}/drive/root/children", USER_ID)
        },
        {
            "id": "5",
            "method": "GET",
            "url": format!("/users/{}/drive/special/documents", USER_ID)
        }
    ]
});

let recv = client
    .v1()
    .batch(&json)
    .send();

loop {
    match recv.recv() {
        Ok(delta) => {
            match delta {
                Delta::Next(response) => {
                    println!("{:#?}", response);
                },
                Delta::Done(err) => {
                    println!("Finished");

                    // If the delta request ended in an error Delta::Done
                    // will return Some(GraphFailure)
                    if let Some(err) = err {
                        println!("Error: {:#?}", err);
                        println!("Description: {:#?}", err.description());
                    }

                    // All next links have been called.
                    // Break here. The channel has been closed.
                    break;
                },
            }
        },
        Err(e) => {
            println!("{:#?}", e.description());
            break;
        },
    }
}

For those interested in the code itself

Build

Normal Rust build using cargo.

$ cargo build

Docs

Of the portions that are implemented there are also examples and docs. Run:

$ cargo doc --no-deps --open

There are several parts to this project:

  • graph-oauth: OAuth client for getting access/refresh tokens from the Graph api.
  • graph-error: Errors that come back from the Graph Api.
  • graph-codegen: OpenApi parser and generator specifically for the Graph Api's.
  • graph-core: Common types shared across all or multiple parts of the project
  • test-tools: Helps facilitate project testing.
  • graph-rs (src directory): The Graph client for interacting with the Graph Api including the Api's generated from the OpenApi config. The oauth client is also reexported from here.

Testing

The project does validation testing for the Graph Api's using a developer sandbox to ensure the implementation provided here works correctly. However, the total amount of individual requests that can be called and that is provided in this project is well into the hundreds, and some areas are lacking in coverage. The goal is to cover the main parts of each Api.

Tests are run on Ubuntu Linux and Windows 10 instances.

graph-rs versions before 12/13/2020

The graph-rs project is now published on crates.io and that is the recommended version to use. Because of the many changes that came with publishing, if you still need to migrate or would like to use the previous version then you can use the v2master branch which is still the same as the master branch before it was published as a crate.

Comments
  • Reports API

    Reports API

    Meta bug for Reports API. Reference: https://docs.microsoft.com/en-us/graph/api/resources/report?view=graph-rest-1.0

    • [ ] Microsoft Teams device usage #232
    • [ ] Microsoft Teams user activity #232
    • [ ] Outlook activity #233
    • [ ] Outlook app usage #233
    • [ ] Outlook mailbox usage #233
    • [ ] Office 365 activiations #234
    • [ ] Office 365 active usres #234
    • [ ] Office 365 groups activity #234
    • [ ] OneDrive activity #235
    • [ ] OneDrive Usage #235
    • [ ] SharePoint activity #235
    • [ ] SharePoint site usage #235
    • [ ] Skype for Business activity #236
    • [ ] Skype for Business device usage #236
    • [ ] Skype for Business organizer activity #236
    • [ ] Skype for Business participant activity #236
    • [ ] Skype for Business peer-to-peer activity #236
    • [ ] Yammer activity #237
    • [ ] Yammer device usage #237
    • [ ] Yammer groups activity #237
    Meta reports 
    opened by sreeise 17
  • 0.1.2 Regressions and breaking changes

    0.1.2 Regressions and breaking changes

    Hi, thanks a lot for that release but unfortunately I found a few problems with it.

    Regressions:

    • it is no longer possible to execute multiple requests with the same async client. See https://gist.github.com/DevLazio/3afd1c221dd58b3949da9ced624aede3 for example. When updating to 0.1.2 I had to add line 37 to fix a deadlock.
    • Errors are no longer Send + Sync

    Breaking changes:

    • deserializing to a struct with the json() method require encapsulating the type with GraphResponse<>
    let license_details: LicenseDetails = client
                .v1()
                .users()
                .id(user_id)
                .list_license_details()
                .json()
                .await?;
    
    Ok(license_details.value)
    

    became

      let license_details: GraphResponse<LicenseDetails> = client
                .v1()
                .users()
                .id(user_id)
                .list_license_details()
                .json()
                .await?;
    
      Ok(license_details.into_body().value)
    

    and the documentation / readme should reflect that

    opened by DevLazio 16
  • PANIC: GraphDiscovery::Tenant().oauth() under Tokio

    PANIC: GraphDiscovery::Tenant().oauth() under Tokio

    If you run the following test:

        #[tokio::test(core_threads = 4)]
        async fn get_tennant_disco_tokio() {
            let oauth: GraphOAuth = 
                match GraphDiscovery::Tenant(TST_MSGRAPH_TENNANT.to_owned()).oauth()
                {
                    Ok(tmpoauth) => tmpoauth,
                    Err(err) => {
                        let msg = format!("[get_tennant_disco_tokio()]:, {:?}", err);
                        panic!(msg);
                    },
                };
            println!("[get_tennant_disco_tokio()]:, {:?}", oauth);
        }
    
    

    It fails in MicrosoftSigningKeysV2 = Commons::signing_keys :

    let client = reqwest::blocking::Client::builder().build()?; ------------------------^^^^^^------- The Client is using the reqwest blocking client... Is there a flag to force async / non-blocking ?

    opened by JRAndreassen 13
  • Graph concurrency deadlock

    Graph concurrency deadlock

    It looks like I found another way to deadlock the application when preparing bunch of requests at the same time.

    This time, I was able to reproduce the deadlock without send the requests : let _a = client .v1(); is enough to trigger it as shown here.

    Requesting with reqwest does not trigger the deadlock. On my computer, this program deadlock after 128 "Fetching license detail for /.." but when I uncomment the next line ".users()" the deadlock appears twice as fast than without this line, after 64 calls. Uncommenting the next line divide again the number of calls required by two, etc. In the end, only 16 calls are required to trigger the deadlock with this code :

     let _license_details: GraphResponse<LicenseDetails> = client
              .v1()
              .users()
              .id(user_id)
              .list_license_details()
              .json().await?;
    

    I tried :

    • adding a tracing debug
    • using tokio-console to look for locked mutexes (not the case)
    • upgrading every dependency of every crate of graph_rs (except handlebars)

    and I still have no clue.

    bug 
    opened by DevLazio 11
  • tokio-runtime-worker panicked...

    tokio-runtime-worker panicked...

    Following this, or any of the oauth examples like this one:

    https://github.com/sreeise/graph-rs/blob/248f9298551e721042b7ee9a27e99ede3e5f0cce/examples/oauth_web_server_client_credentials.rs#L76

    Results in: thread 'tokio-runtime-worker' panicked at 'Cannot drop a runtime in a context where blocking is not allowed.

    Not Rust smart, so don't really know how to fix, or workaround. Basic understanding is that the access_token request can't happen in the existing async process. Any help?

    opened by kitplummer 8
  • AsyncAccessTokenGrant to access_token().send().await failing.

    AsyncAccessTokenGrant to access_token().send().await failing.

    Am sure it is something I've misconfigured on my side. That request is returning a 400.

    If I use the code produced in the first bit (in a Postman POST) I can get the token. Feeling sheepish - but can't seem to figure it out. The GraphError isn't really pointing me to anything obvious. Any ideas?

    HERE2: AsyncAccessTokenGrant { oauth: AccessToken { access_token: "[REDACTED]", credentials: {"access_token_url": "https://login.microsoftonline.com/common/oauth2/v2.0/token", "authorization_url": "https://login.live.com/oauth20_authorize.srf?", "client_id": "[REDACTED]", "client_secret": "[REDACTED]", "code": "[REDACTED]", "redirect_uri": "http://localhost:8000/redirect"}, scopes: {"Tasks.ReadWrite"} }, grant: ClientCredentials }
    
    
    ERROR: Graph error:
    GraphError {
        headers: Some(
            GraphHeaders {
                url: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
                status: 400,
                header_map: {
                    "cache-control": "no-store, no-cache",
                    "pragma": "no-cache",
                    "content-type": "application/json; charset=utf-8",
                    "expires": "-1",
                    "strict-transport-security": "max-age=31536000; includeSubDomains",
                    "x-content-type-options": "nosniff",
                    "p3p": "CP=\"DSP CUR OTPi IND OTRi ONL FIN\"",
                    "x-ms-request-id": "c666ee00-789f-4c30-be34-98bca041c302",
                    "x-ms-ests-server": "2.1.13562.12 - SCUS ProdSlices",
                    "x-xss-protection": "0",
                    "set-cookie": "fpc=AgHJgu2OQbtMvKCHI2JCvY4; expires=Tue, 11-Oct-2022 18:20:36 GMT; path=/; secure; HttpOnly; SameSite=None",
                    "set-cookie": "x-ms-gateway-slice=estsfd; path=/; secure; httponly",
                    "set-cookie": "stsservicecookie=estsfd; path=/; secure; httponly",
                    "date": "Sun, 11 Sep 2022 18:20:36 GMT",
                    "content-length": "548",
                },
            },
        ),
        code: 400,
        error_message: ErrorMessage {
            error: None,
        },
    }
    
    opened by kitplummer 7
  • AccessToken-May-be-String

    AccessToken-May-be-String

    There are some cases where the "AccessToken.expires_in" is returned as String.

    This change makes the structure / Deserialization insensitive. It will take either

    opened by JRAndreassen 6
  • Replace rocket with warp

    Replace rocket with warp

    Closes #313

    • Replaces the examples' rocket server with a similar warp test server. The test server supports graceful shutdown and a serve_once function that will automatically shut down the server after one request (as is often the case with the redirection functions)
    • Updates project dependencies for tokio/reqwest/etc to remove some of the duplicates
    • Also includes some clippy test/example fixes.
    opened by ecclarke42 4
  • Move to stable

    Move to stable

    I'd love to use this library for a work project, but I'm not sure I'm willing to move everything to nightly for it. Here's a quick stab at building it on stable, with some updated/relaxed dependencies!

    At the very least, this will build on stable, but tests still require nightly for some of the proc_macro/codegen parts.

    The nightly parts still present are gated by a #[cfg(nightly)], but I'm not sure those are all necessary, since they primarily deal with NoneError, which is pretty easily replaced by .ok_or(...). I may add another commit adding thiserror support to clean up GraphFailure a bit.

    Would love some feedback or ideas on how to take this the rest of the way!

    Ref: #290

    opened by ecclarke42 4
  • Scale back nightly version to get it closer to stable and eventually to stable

    Scale back nightly version to get it closer to stable and eventually to stable

    @sreeise ...

    Is there a way to get rid of the requirement to use nightly unstable features...

    The requirement is causing all kinds of other unstable features to be included.

    One of which causes a runaway process in the futures library...

    So, is there a way to at least make it optional ?

    Thanks JR

    opened by JRAndreassen 4
  • Create Team results in Reqwest Error

    Create Team results in Reqwest Error

    So when creating a Team with

    graph.v1().teams().create_team(...)
    

    the intended response from graph will have content length zero.

    However, currently, even on a successfull request, the response returned by graph-rs is

    Err(ReqwestError(reqwest::Error { kind: Decode, source: Error("EOF while parsing a value", line: 1, column: 0) }))
    

    This is most likely because the response is in fact empty, and this is not an error.

    This is in so far problematioc that the graph response still has some headers that are needed to get the id of the newly created team.

    but since a request error is returned, the headers can not be retrived.

    Test code:

    let graph = ...;
    let json = serde_json::json!({
      "[email protected]": "https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
      "displayName": "My Sample Team",
      "description": "My Sample Team’s Description"
    });
    let resp = graph.v1().teams().create_team(&graph_team).send().await;
    std::println!("{resp:?}");
    
    bug 
    opened by JoschuaL 3
  • Make it easy to perform retries on requests - error results should include relevant info like request url, headers, etc.

    Make it easy to perform retries on requests - error results should include relevant info like request url, headers, etc.

    The client does not have a way to handle 429 responses (too many requests) that results from throttling. There should be a way to retry the requests that failed.

    • It is difficult handle retries.
    • GraphRequest<T>` cannot be recreated in anyway.
    • GraphResponse<T> has information necessary for a retry in the event of a throttle occurring. However because this is a 429 error response the api client returns a GraphResult with an error object and this does not provide any relevant information to make a retry request.
    • GraphResponse does not have relevant information for retrying a request.
    opened by sreeise 9
  • Provide documentation regarding next links and ways to continue requesting next links

    Provide documentation regarding next links and ways to continue requesting next links

    Discussed in https://github.com/sreeise/graph-rs/discussions/360

    Originally posted by DevLazio June 17, 2022 Currently, if you request an api which provide a list you may receive a response containing a next_link attribute. For example, v1().users().list_user() by default will only return 100 users, and a maximum of 999 can be ask with the .top("999") method. So if you have more than a thousand users in your Azure AD you will need to use the next_link attribute to send another request for a new batch of users, append it to the previous list, rinse and repeat. This means:

    • a lot a boilerplate code
    • new users of the crate may not be aware of the limitations before using their code on a production environnement

    Should we do something about it ? A first step could be to add some kind of warning in the documentation. Another step could be to provide a method to do that automatically.

    What's your take on this ?

    opened by sreeise 0
  • start delta requests from delta token

    start delta requests from delta token

    Hi,

    is there a way to request /root/delta starting from a delta token that is acquired beforehand? As my Rust knowledge and experience is limited my assumptions may be wrong but I came up with the following ideas.

    Add the delta token as parameter to the delta() function like in the official C# SDK. var delta = await graphClient.Me.Drive.Root .Delta("1230919asd190410jlka") .Request() .GetAsync(); which would lead to something similar let mut delta_recv = client.v1().drive(tok.drive_id).delta(tok.last_token).send().await;

    or

    Add the token query parameter to the OData query parameters like filter or select.

    Option 1 would be more inline with other SDK and the separation between what is OData and what is Graph API specific functionality. But meddling with codegen/macros is not something I feel comfortable with.

    Option 2 is what I was able to do to get on with my learning project but consider not wise for API design reasons.

    opened by smndtrl 7
  • Make it easier to add a new api's.

    Make it easier to add a new api's.

    When a new api request client needs to be generated there are several parts that need to be updated in the graph-codegen crate. This is mostly due to the various steps that are taken when parsing such as adding custom methods not in the OpenApi config, adding configs to the parser to modify URL paths, adding configs to the parser for linking between clients, etc. A good portion of this can be changed to one configuration and added to the parser all at once. Additionally, there are parts that can be added automatically based on certain criteria found when parsing.

    codegen 
    opened by sreeise 0
Releases(v0.3.0)
  • v0.3.0(Aug 23, 2022)

    • Adds Identity Governance apis
    • Updates Teams api to spread out requests among multiple clients.
    • Fixes issue incorrectly assuming teams api returing response body on post request.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Apr 22, 2022)

    Highlights:

    • Fixes concurrency and deadlock issues: https://github.com/sreeise/graph-rs/issues/349
    • Adds custom timeouts: https://github.com/sreeise/graph-rs/issues/352
    • Adds custom host endpoints for the graph api instead of using the v1 or beta endpoint: https://github.com/sreeise/graph-rs/issues/344
    • Updates graph-oauth crate to defer errors instead of unwrapping when requesting authorization and access/refresh tokens: https://github.com/sreeise/graph-rs/issues/337

    Special thanks to @DevLazio for making this one happen. :rocket:

    Source code(tar.gz)
    Source code(zip)
  • v0.1.4(Jan 31, 2022)

  • v0.1.3(Jan 15, 2022)

  • v0.1.2-fix(Jan 11, 2022)

    • OpenApi modals closely aligned with OpenApi specification.
    • Reports API implemented.
    • Rewrite of how download requests work. For requests that make it possible to download a file, you can now also get this same file data in other forms such as text or bytes.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Aug 19, 2021)

    Changes the OData query methods to use $ as a prefix for all V1 and beta requests. Originally the http client was not including the $ prefix but an issue was found where only certain V1 endpoints support OData queries without the $ prefix. Per https://docs.microsoft.com/en-us/graph/query-parameters:

    On the beta endpoint, the $ prefix is optional. For example, instead of $filter, you can use filter. On the v1 endpoint, the $ prefix is optional for only a subset of APIs. For simplicity, always include $ if using the v1 endpoint.

    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(Jan 19, 2021)

Owner
Sean Reeise
Software Engineer at BoomTown. Graduated from Liberty University
Sean Reeise
A graph library for Rust.

Gamma A graph library for Rust. Gamma provides primitives and traversals for working with graphs. It is based on ideas presented in A Minimal Graph AP

Metamolecular, LLC 122 Dec 29, 2022
Simple but powerful graph library for Rust

Graphlib Graphlib is a simple and powerful Rust graph library. This library attempts to provide a generic api for building, mutating and iterating ove

Purple Protocol 177 Nov 22, 2022
🦀 Rust Graph Routing runtime for Apollo Federation 🚀

Apollo Router The Apollo Router is a configurable, high-performance graph router for a federated graph. Getting started Follow the quickstart tutorial

Apollo GraphQL 502 Jan 8, 2023
Rust library for of graph ensembles

Rust library for random graph ensembles Minimal Rust version: 1.55.0 Implements simple sampling and monte carlo (or rather markov-) steps, that can be

Yannick Feld 2 Dec 14, 2022
A Graph implemented using nothing but `Vec`s in rust

VecGraph A Graph implemented using nothing but Vecs in rust. Details The graph is implemented using two Vecs: nodes and edges. nodes stores "nodes". w

null 1 Jan 27, 2022
GraphScope: A One-Stop Large-Scale Graph Computing System from Alibaba

A One-Stop Large-Scale Graph Computing System from Alibaba GraphScope is a unified distributed graph computing platform that provides a one-stop envir

Alibaba 2.2k Jan 1, 2023
A simple and elegant, pipewire graph editor

pw-viz A simple and elegant, pipewire graph editor This is still a WIP, node layouting is kinda jank at the moment. Installation A compiled binary is

null 180 Dec 27, 2022
A graph crate with simplicity in mind

A graph crate with simplicity in mind. Prepona aims to be simple to use (for users of the crate) and develop further (for contributors). Nearly every

Mohamad Amin Rayej 80 Dec 15, 2022
Simple, performant graph generator for Feynman diagrams* ⚛️

Feynman diagram generator ⚛️ A simple generator of "Feynman diagram" permutations (as defined by problem 781). Incrementally builds isomorphically uni

eugene huang 3 Jan 1, 2023
Theorem relational dependencies automatic extraction and visualization as a graph for Lean4.

Lean Graph Interactive visualization of dependencies for any theorem/definitions in your Lean project. How to use In your browser: lean-graph.com Or r

Patrik Číhal 8 Jan 3, 2024
A low-overhead Vulkan-like GPU API for Rust.

Getting Started | Documentation | Blog gfx-rs gfx-rs is a low-level, cross-platform graphics and compute abstraction library in Rust. It consists of t

Rust Graphics Mages 5.2k Jan 8, 2023
Safe and rich Rust wrapper around the Vulkan API

Vulkano See also vulkano.rs. Vulkano is a Rust wrapper around the Vulkan graphics API. It follows the Rust philosophy, which is that as long as you do

null 3.6k Jan 3, 2023
A vector graphics renderer using OpenGL with a Rust & C API.

bufro A vector graphics renderer using OpenGL with a Rust & C API. A Rust example can be found in examples/quickstart.rs (using glutin). A C example c

Aspect 9 Dec 15, 2022
Rust bindings to bgfx, a cross-platform, graphics API agnostic

Rust bindings to bgfx, a cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.

Daniel Collin 65 Dec 24, 2022
A toy ray tracer in Rust

tray_rust - A Toy Ray Tracer in Rust tray_rust is a toy physically based ray tracer built off of the techniques discussed in Physically Based Renderin

Will Usher 492 Dec 19, 2022
A complete harfbuzz's shaping algorithm port to Rust

rustybuzz rustybuzz is a complete harfbuzz's shaping algorithm port to Rust. Matches harfbuzz v2.7.0 Why? Because you can add rustybuzz = "*" to your

Evgeniy Reizner 310 Dec 22, 2022
An OpenGL function pointer loader for Rust

gl-rs Overview This repository contains the necessary building blocks for OpenGL wrapper libraries. For more information on each crate, see their resp

Brendan Zabarauskas 621 Dec 17, 2022
Safe OpenGL wrapper for the Rust language.

glium Note to current and future Glium users: Glium is no longer actively developed by its original author. That said, PRs are still welcome and maint

null 3.1k Jan 1, 2023
GLFW3 bindings and idiomatic wrapper for Rust.

glfw-rs GLFW bindings and wrapper for The Rust Programming Language. Example extern crate glfw; use glfw::{Action, Context, Key}; fn main() { le

PistonDevelopers 546 Jan 3, 2023