Build forms with GraphQL

#whoami
Charly POLY - Senior Software Engineer at



#whoami

I
Single Page Applications
Front-end development
❤️
Single Page Applications

State management
Crypto
Offline capabilities
Routing
Rendering
PWA
Single Page Applications

Forms =
manual and repetitive task
Forms: glue between UI and APIs




// Render Prop
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import { CustomInputComponent, CustomPasswordComponent } from './common/components';
import { UserService } from './services/UserService';
const Basic = () => (
<Formik
validate={values => {
let errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => UserService.update(values, setSubmitting) }
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" component={CustomInputComponent} />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" component={CustomPasswordComponent} />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
export default Basic;
Forms: glue between UI and APIs


Forms: glue between UI and APIs

"Forms handle the experience that users have with data"

Story: Improving forms development
Speeding up form development

class Form extends ModuleForm {
fields: FieldsDefinitions = {
id: 'none',
email: 'none',
picture_path: {
type: 'image', transformations: 'h_200,w_200,r_max,c_fill'
},
first_name: 'string*',
last_name: 'string*',
username: 'string*',
job_title: 'string',
company_name: 'string',
language: {
type: 'select*',
component: LanguageSelectView,
valueProperty: 'code',
values: supportedLanguages,
moduleName: 'attachment'
}
};
constructor() {
super('UserForm', 'user');
}
}
Speeding up form development




Speeding up form development

- Too many abstractions
- Not flexible
- Not the "React way"
Not the proper solution

Leveraging GraphQL
to improve form development
What is GraphQL?

HTTP requests
SPA
GraphQL API
What is GraphQL?

GraphQL Schema
Data types
Queries
Mutations
GraphQL API
How to leverage GraphQL?

GraphQL mutation design
mutation(user: UserInputType!, company: CompanyInputType) {
create_account(user: $user, company: $company) {
user {
id
}
}
}
How to leverage GraphQL?

1. GraphQL mutations are based on business logic
mutation
Onboarding
Form
GraphQL API
User model
Company model
How to leverage GraphQL?

introspection
query
GraphQL API
2. GraphQL introspection
{
"name": "createAccount",
"__typename": "__Field",
"isDeprecated": false,
"deprecationReason": null,
"args": [
{
"name": "user",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "InputType",
"name": "UserInputType",
"ofType": null,
"__typename": "__Type"
},
"__typename": "__Type"
},
"defaultValue": null,
"__typename": "__InputValue"
},
// ...
}
How to leverage GraphQL?

2. GraphQL introspection
introspection
query
GraphQL API
You can create an Account by providing
a mandatory User type and
an optional Company type
GraphQL for forms

Mutation =
similar to Form UI
Mutation name =
fields + requirements
GraphQL for forms


<Frontier />

<Frontier />
Simplicity
Frontier forms

Simplicity
<Frontier mutation={mutation} client={client} initialValues={{ user: { email: 'hello@charlypoly.com ' } }}>
{
({ state, modifiers, form }) => {
return (
<form onSubmit={modifiers.save}>
<h2>Create a user</h2>
<p>
<label htmlFor="name">Name*</label> <br />
<input
type="text"
name="name"
value={state.values.user.name} onChange={modifiers.user.name.change}
/>
{
state.errors.user && state.errors.user.name &&
<p>
Error: "{state.errors.user.name}"
</p>
}
</p>
<p>
<input type="submit" value="Save" />
</p>
</form>
)
}
}
</Frontier>

<Frontier />
Full data lifecycle management
Frontier forms

Full-data lifecycle management
GraphQL
final-form
Apollo GraphQL
Fields definitions
Form state
Save data

<Frontier />
UI-Kit
Frontier forms

UI-Kit
const mutation = gql`
mutation ($user: UserInputType!) {
createUser(user: $user) {
...User
}
}
`;
<Frontier mutation={mutation} client={client} uiKit={ApplicationUIkit} />
Frontier forms

UI-Kit


<Frontier />
Flexible
Frontier forms
Flexible
<Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}>
{
({ form, kit }) => {
return (
<form className='ui form' onSubmit={(e) => { e.preventDefault(); form.submit(); }}>
<div>
{kit.company()}
</div>
<Message
info
header='Is my company already registered?'
list={[
'If your company is already registred under a Business plan, please do register using the Business form',
]}
/>
<br />
<br />
<div>
{kit.email()}
</div>
<br />
<div>
{kit.firstname()}
</div>
<br />
<div>
{kit.lastname()}
</div>
<p>
<input type="submit" value="Save" className="ui button" />
</p>
</form>
)
}
}
</Frontier>
Frontier forms
Flexible

Frontier forms

- Full data lifecycle management: state, validation, save
- UI-kit full rendering: bring a consistent experience to your users
- Simple and iterative: choose your form development flow
A new form development experience
Frontier forms: demos

How to:
- Define and use a UI-Kit for your application
- Advanced use-cases
(validations & complex types)
Frontier: built for the future

Frontier Core
Frontier React
Frontier Data
- Apollo GraphQL
- ajv
- final-form
Frontier: built for the future

- Swagger support
- More flavours: Vue.js, Angular and React Native
- API improvements
frontier-forms.dev 👀

Thank you!




Build forms with GraphQL - React Europe 2019
By Charly Poly
Build forms with GraphQL - React Europe 2019
- 1,745