mirror of
https://github.com/twentyhq/twenty.git
synced 2024-10-27 03:33:21 +03:00
2915 rest api documentation (#3020)
* Init rest-api page * Add ugly form to fetch open api schema * Clean code * Make the form design more acceptable * Update doc * Use local storage * Update design * Add isLoading * Fix typo * Fix long lines * Code review returns * Remove staging and local url from servers
This commit is contained in:
parent
9f6d476351
commit
3ac4102c3c
@ -1,9 +1,30 @@
|
|||||||
---
|
---
|
||||||
title: Rest API
|
title: REST API
|
||||||
sidebar_position: 3
|
sidebar_position: 3
|
||||||
sidebar_class_name: coming-soon
|
|
||||||
sidebar_custom_props:
|
sidebar_custom_props:
|
||||||
icon: TbApi
|
icon: TbApi
|
||||||
---
|
---
|
||||||
|
|
||||||
Coming soon!
|
To use the REST API, you will need an API key.
|
||||||
|
Connect to your Twenty account and follow the following
|
||||||
|
[documentation](user-guide/integrations/generating-api-keys.mdx) to generate one
|
||||||
|
|
||||||
|
## Using Postman?
|
||||||
|
|
||||||
|
You can use [Postman](https://www.postman.com/) to interact with your Twenty objects using the API.
|
||||||
|
You will need to provide your API key as a Bearer token,
|
||||||
|
see [Bearer Token Postman Doc](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token)
|
||||||
|
if needed.
|
||||||
|
|
||||||
|
## Programmatic use?
|
||||||
|
|
||||||
|
You can call the REST API in your application using this endpoint
|
||||||
|
[https://api.twenty.com](https://api.twenty.com).
|
||||||
|
You will need to provide your API key as a Bearer token in
|
||||||
|
your `headers.Authorization = 'Bearer <YOUR_API_KEY>'`.
|
||||||
|
|
||||||
|
## Try the REST API Playground
|
||||||
|
|
||||||
|
You can use the browser-based, interactive
|
||||||
|
[REST API playground documentation](https://docs.twenty.com/rest-api)
|
||||||
|
to Create, Read, Update or Delete your workspace objects.
|
||||||
|
@ -17,11 +17,11 @@ Sync Twenty with 3000+ apps using [Zapier](https://zapier.com/), and automate yo
|
|||||||
2. Click on `+ Create Zap` in the left sidebar.
|
2. Click on `+ Create Zap` in the left sidebar.
|
||||||
3. Choose the application you want to set as the trigger. A trigger refers to an event that starts the automation.
|
3. Choose the application you want to set as the trigger. A trigger refers to an event that starts the automation.
|
||||||
4. Select Twenty as the action. An action is the event performed whenever an application triggers an automation. [Learn more about triggers and actions in Zapier.](https://zapier.com/how-it-works)
|
4. Select Twenty as the action. An action is the event performed whenever an application triggers an automation. [Learn more about triggers and actions in Zapier.](https://zapier.com/how-it-works)
|
||||||
5. Once you choose the Twenty account that you want to use for your automation, you'll have to authorize it by adding an API key. You can learn [how to generate your API key here.](generating-api-keys.mdx)
|
5. Once you choose the Twenty account that you want to use for your automation, you'll have to authorize it by adding an API key. You can learn [how to generate your API key here.](user-guide/integrations/generating-api-keys.mdx)
|
||||||
6. Enter your API key and click on 'Yes, Continue to Twenty.'
|
6. Enter your API key and click on 'Yes, Continue to Twenty.'
|
||||||
|
|
||||||
<div style={{textAlign: 'center'}}>
|
<div style={{textAlign: 'center'}}>
|
||||||
<img src="/img/user-guide/connect-zapier.png" alt="Connect Twenty to Zapier" />
|
<img src="/img/user-guide/connect-zapier.png" alt="Connect Twenty to Zapier" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
You can now continue creating your automation!
|
You can now continue creating your automation!
|
||||||
|
@ -33,6 +33,7 @@ const config = {
|
|||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
locales: ["en"],
|
locales: ["en"],
|
||||||
},
|
},
|
||||||
|
plugins: ['docusaurus-node-polyfills'],
|
||||||
presets: [
|
presets: [
|
||||||
[
|
[
|
||||||
"classic",
|
"classic",
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
"@docusaurus/core": "^3.0.0",
|
"@docusaurus/core": "^3.0.0",
|
||||||
"@docusaurus/preset-classic": "^3.0.0",
|
"@docusaurus/preset-classic": "^3.0.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
|
"@stoplight/elements": "^7.15.4",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
|
"docusaurus-node-polyfills": "^1.0.0",
|
||||||
"graphiql": "^2.4.7",
|
"graphiql": "^2.4.7",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"iframe-resizer-react": "^1.1.0",
|
"iframe-resizer-react": "^1.1.0",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { createGraphiQLFetcher } from "@graphiql/toolkit";
|
import { createGraphiQLFetcher } from "@graphiql/toolkit";
|
||||||
import { GraphiQL } from "graphiql";
|
import { GraphiQL } from "graphiql";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
import Layout from "@theme/Layout";
|
import Layout from "@theme/Layout";
|
||||||
import BrowserOnly from "@docusaurus/BrowserOnly";
|
import BrowserOnly from "@docusaurus/BrowserOnly";
|
||||||
|
|
||||||
@ -16,9 +15,7 @@ const GraphiQLComponent = () => {
|
|||||||
window.localStorage.setItem("graphiql:theme", "light");
|
window.localStorage.setItem("graphiql:theme", "light");
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetcher = createGraphiQLFetcher({
|
const fetcher = createGraphiQLFetcher({url: "https://api.twenty.com/graphql"});
|
||||||
url: "https://api.twenty.com/graphql",
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<div className="fullHeightPlayground">
|
<div className="fullHeightPlayground">
|
||||||
<GraphiQL fetcher={fetcher} />;
|
<GraphiQL fetcher={fetcher} />;
|
||||||
|
67
packages/twenty-docs/src/pages/rest-api.css
Normal file
67
packages/twenty-docs/src/pages/rest-api.css
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 90vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
text-align: center;
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: #16233f;
|
||||||
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
padding: 4px;
|
||||||
|
margin: 20px 0 5px 0;
|
||||||
|
max-width: 460px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-invalid {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.not-visible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
color: #16233f;
|
||||||
|
font-size: 2rem;
|
||||||
|
animation: animate 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(720deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 50px;
|
||||||
|
}
|
114
packages/twenty-docs/src/pages/rest-api.tsx
Normal file
114
packages/twenty-docs/src/pages/rest-api.tsx
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import Layout from "@theme/Layout";
|
||||||
|
import BrowserOnly from "@docusaurus/BrowserOnly";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { API } from '@stoplight/elements';
|
||||||
|
import '@stoplight/elements/styles.min.css';
|
||||||
|
import './rest-api.css'
|
||||||
|
import { parseJson } from "nx/src/utils/json";
|
||||||
|
import { TbLoader2 } from "react-icons/tb";
|
||||||
|
|
||||||
|
type TokenFormProps = {
|
||||||
|
onSubmit: (token: string) => void,
|
||||||
|
isTokenValid: boolean,
|
||||||
|
isLoading: boolean,
|
||||||
|
token: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const TokenForm = ({onSubmit, isTokenValid, token, isLoading}: TokenFormProps)=> {
|
||||||
|
const updateToken = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
localStorage.setItem('TryIt_securitySchemeValues', JSON.stringify({bearerAuth: event.target.value}))
|
||||||
|
onSubmit(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isTokenValid && (
|
||||||
|
<div>
|
||||||
|
<div className='container'>
|
||||||
|
<form className="form">
|
||||||
|
<label>
|
||||||
|
To load your REST API schema, <a className='link' href='https://app.twenty.com/settings/developers/api-keys'>generate an API key</a> and paste it here:
|
||||||
|
</label>
|
||||||
|
<p>
|
||||||
|
<input
|
||||||
|
className={(token && !isLoading) ? "input invalid" : "input"}
|
||||||
|
type='text'
|
||||||
|
disabled={isLoading}
|
||||||
|
placeholder='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMD...'
|
||||||
|
defaultValue={token}
|
||||||
|
onChange={updateToken}
|
||||||
|
/>
|
||||||
|
<p className={`token-invalid ${(!token || isLoading )&& 'not-visible'}`}>Token invalid</p>
|
||||||
|
<div className='loader-container'>
|
||||||
|
<TbLoader2 className={`loader ${!isLoading && 'not-visible'}`} />
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RestApiComponent = () => {
|
||||||
|
const [openApiJson, setOpenApiJson] = useState({})
|
||||||
|
const [isTokenValid, setIsTokenValid] = useState(false)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const storedToken = parseJson(localStorage.getItem('TryIt_securitySchemeValues'))?.bearerAuth ?? ''
|
||||||
|
|
||||||
|
const validateToken = (openApiJson) => setIsTokenValid(!!openApiJson.tags)
|
||||||
|
|
||||||
|
const getJson = async (token: string ) => {
|
||||||
|
setIsLoading(true)
|
||||||
|
return await fetch(
|
||||||
|
"https://api.twenty.com/open-api",
|
||||||
|
{headers: {Authorization: `Bearer ${token}`}}
|
||||||
|
)
|
||||||
|
.then((res)=> res.json())
|
||||||
|
.then((result)=> {
|
||||||
|
validateToken(result)
|
||||||
|
setIsLoading(false)
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.catch(() => setIsLoading(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitToken = async (token) => {
|
||||||
|
if (isLoading) return
|
||||||
|
const json = await getJson(token)
|
||||||
|
setOpenApiJson(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
(async ()=> {
|
||||||
|
await submitToken(storedToken)
|
||||||
|
})()
|
||||||
|
},[])
|
||||||
|
|
||||||
|
return isTokenValid !== undefined && (
|
||||||
|
<>
|
||||||
|
<TokenForm
|
||||||
|
onSubmit={submitToken}
|
||||||
|
isTokenValid={isTokenValid}
|
||||||
|
isLoading={isLoading}
|
||||||
|
token={storedToken}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
isTokenValid && (
|
||||||
|
<API
|
||||||
|
apiDescriptionDocument={JSON.stringify(openApiJson)}
|
||||||
|
router="hash"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const restApi = () => (
|
||||||
|
<Layout
|
||||||
|
title="REST API Playground"
|
||||||
|
description="REST API Playground for Twenty"
|
||||||
|
>
|
||||||
|
<BrowserOnly>{() => <RestApiComponent />}</BrowserOnly>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default restApi;
|
@ -2,6 +2,7 @@
|
|||||||
// This file is not used in compilation. It is here just for a nice editor experience.
|
// This file is not used in compilation. It is here just for a nice editor experience.
|
||||||
"extends": "@docusaurus/tsconfig//tsconfig.json",
|
"extends": "@docusaurus/tsconfig//tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "."
|
"baseUrl": ".",
|
||||||
|
"jsx": "react"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,10 @@ export const baseSchema = (frontBaseUrl: string): OpenAPIV3.Document => {
|
|||||||
},
|
},
|
||||||
// Testing purposes
|
// Testing purposes
|
||||||
servers: [
|
servers: [
|
||||||
{
|
|
||||||
url: 'http://localhost:3000',
|
|
||||||
description: 'Local Development',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://api-main.twenty.com/',
|
|
||||||
description: 'Staging Development',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
url: 'https://api.twenty.com/',
|
url: 'https://api.twenty.com/',
|
||||||
description: 'Production Development',
|
description: 'Production Development',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
url: '/',
|
|
||||||
description: 'Current Host',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
securitySchemes: {
|
securitySchemes: {
|
||||||
|
Loading…
Reference in New Issue
Block a user