microsoftgraph / microsoft-graph-toolkit

Authentication Providers and UI components for Microsoft Graph 🦒
https://docs.microsoft.com/graph/toolkit/overview
Other
929 stars 291 forks source link

New component: mgt-post #1240

Open waldekmastykarz opened 3 years ago

waldekmastykarz commented 3 years ago

Proposal: New component: mgt-post

Description

Add a new component (mgt-post) that allows you to post data to Microsoft Graph APIs

Rationale

A generic Post component would enable many scenarios powered by Microsoft Graph, such as creating to do items, scheduling meetings, creating list items, uploading files, etc. Having an MGT component that does this, would simplify communication with Graph and let developers focus on building the UI.

Preferred Solution

Properties

Attribute Property Description
endpoint endpoint The endpoint to submit the data to
scopes scopes Optional array of strings if using the property or a comma delimited scope if using the attribute. The component will use these scopes (with a supported provider) to ensure that the user has consented to the right permission.
version version Optional API version to use when making the request. Default is v1.0.
N/A data Data to send to Microsoft Graph. Must match the payload required by the API specified in the endpoint property
N/A response Read-only response from Microsoft Graph if request was successful.
N/A error Read-only error from Microsoft Graph if request was not successful.

Events

Templates

Additional Context

For simplicity, we could start with the Post component supporting posting only JSON data. Later, we could extend it with support for uploading files as well as other update methods like PATCH or PUT.

Should we have support for validating the data before submitting it (eg. a separate validate event that occurs before the submit event) or would we rather have developers perform validation inside the submit event and cancel it if the validation failed?

ghost commented 3 years ago

Hello waldekmastykarz, thank you for opening an issue with us!

I have automatically added a "needs triage" label to help get things started. Our team will analyze and investigate the issue, and escalate it to the relevant team if possible. Other community members may also look into the issue and provide feedback 🙌

MrCodeWeaver commented 3 years ago

This is related to https://github.com/microsoftgraph/microsoft-graph-toolkit/issues/870

nmetulev commented 3 years ago

Thanks @waldekmastykarz. How do you see this being used with a form and the data being passed to the mgt-post component? Do we wrap the form inside the component and label fields that should be included in the request somehow? Per the proposal, it looks like the data will need to be passed in JS or JSX, but not in HTML? A code snipper/pseudo code would help

This sounds different from #870. I see #870 as supporting POST requests in mgt-get for POST APIs that fetch data to be rendered, while mgt-post sounds like it is intended only for posting data from forms?

waldekmastykarz commented 3 years ago

That's right. So far my idea was to allow something like:

<mgt-post endpoint="/some/graph/api">
  <template>
    Location: <input name="location"><br>
    ZIP code: <input name="zip"><br>
    <button data-props="{{ @click: submit }}">Submit</button>
  </template>
</mgt-post>

The submit event handler would then get access to the templateContext and be able to extract the data from input fields and create the necessary payload object. That way, developers would retain the maximum flexibility for turning user input into the necessary Graph payload. I don't know if there is anything that we could do to help developers get to the data from input fields (like already exposing them on the event context) or if we'd simply let them get it out themselves from templateContext.

nmetulev commented 3 years ago

Thanks Waldek. Let me try this with a graph example, ex: https://docs.microsoft.com/en-us/graph/api/listitem-create?view=graph-rest-1.0&tabs=http#example

<mgt-post endpoint="sites/{site-id}/lists/{list-id}/items">
  <template>
    Input: <input name="title"><br>
    Color: <input name="color"><br>
    Weight: <input name="weight"><br>
    <button data-props="{{ @click: submit }}">Submit</button>
  </template>
</mgt-post>
let mgtPost = document.querySelector('mgt-post');

mgtPost.addEventListener('submitInitiated', (e) => {
    e.detail.setBody({
        "fields": {
            "Title": e.detail.inputs.title,
            "Color": e.detail.inputs.color,
            "Weight": e.detail.inputs.weight,
        }
    });
});

mgtPost.addEventListener('requestCompleted', (e) => {
    let response = e.detail.response;
    let error = e.detail.error;
});

Is this what you had in mind?

For comparison, here is an example of doing a post without the component in vanila html/js (I'm sure various frameworks do forms differently):

<form>
    Input: <input name="title"><br>
    Color: <input name="color"><br>
    Weight: <input name="weight"><br>
    <button id="submit">Submit</button>
</form>
document.querySelector('button').addEventListener('click', (e) => {
    let form = document.querySelector('form');
    let response = await Providers.client.api('/sites/{site-id}/lists/{list-id}/items')
    .post({
            "fields": {
                "Title": form.elements['title'],
                "Color": form.elements['color'],
                "Weight": form.elements['weight'],
            }
        });
})

IMO, this seems simpler, but it could just be an overly simplified example and I'm not thinking about various complexities.

waldekmastykarz commented 3 years ago

Yes, this is what I've been thinking about. The benefit I see in wrapping it in a Post component is to handle the progress (UI state after submitting the form and before receiving a response from the server) and the error state, and showing the response from the API. In the plain JS approach with the Provider, you'd need to do all of that in code and manipulate DOM yourself, which for complex UI will quickly become tedious.

<mgt-post endpoint="sites/{site-id}/lists/{list-id}/items">
  <template data-type="default">
    Input: <input name="title"><br>
    Color: <input name="color"><br>
    Weight: <input name="weight"><br>
    <button data-props="{{ @click: submit }}">Submit</button>
  </template>
  <template data-type="submitting">
    <mgt-spinner></mgt-spinner> Creating list item...
  </template>
  <template data-type="error">
    The following error has occurred: {{ this.error }}. Please try again.<br>
    Input: <input name="title" value="{{ this.title }}"><br>
    Color: <input name="color" value="{{ this.color }}"><br>
    Weight: <input name="weight" value="{{ this.weight }}"><br>
    <button data-props="{{ @click: submit }}">Submit</button>
  </template>
  <template data-type="submitted">
    Thank you! Created:<br>
    Input: {{ this.title }}<br>
    Color: {{ this.color }}<br>
    Weight: {{ this.weight }}<br>
  </template>
</mgt-post>
sebastienlevert commented 5 months ago

There has been some requests around POST for calling functions vs. creating or updating items. Would this component be more of a mgt-form component? Where it could handle the communication with Graph vs. "just" being a POST? @waldekmastykarz, thoughts?

waldekmastykarz commented 5 months ago

It could be, but I wonder if a more generic post would be an easier place to start and learn about the different use cases.