diff --git a/.prettierignore b/.prettierignore index 896ab5f8f4..4e8fcdd095 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,5 @@ public/ pnpm-lock.yaml -*.mdx !src/pages/blog/2024-04-11-announcing-new-graphql-website/index.mdx !src/pages/blog/2024-08-15-graphql-local-initiative.mdx *.jpg diff --git a/src/app/conf/2023/faq/faq.mdx b/src/app/conf/2023/faq/faq.mdx index 6f952dafdb..569a0b410a 100644 --- a/src/app/conf/2023/faq/faq.mdx +++ b/src/app/conf/2023/faq/faq.mdx @@ -1,109 +1,114 @@ # GraphQLConf FAQ -
{toc.map(({value, id}) => {value})}
+
+ {toc.map(({ value, id }) => ( + + {value} + + ))} +
## Contact Us [#contact] -Answers to many common questions are readily available on this event’s -website. If you cannot find the answer to your question, you are welcome -to contact us by emailing graphql_events@linuxfoundation.org. +Answers to many common questions are readily available on this event’s website. +If you cannot find the answer to your question, you are welcome to contact us by +emailing graphql_events@linuxfoundation.org. ## Confidentiality -We never sell attendee lists or contact information, nor do we authorize -others to do so. If you receive an email claiming to sell an attendee -list for a Linux Foundation event, please forward it to events@linuxfoundation.org. +We never sell attendee lists or contact information, nor do we authorize others +to do so. If you receive an email claiming to sell an attendee list for a Linux +Foundation event, please forward it to events@linuxfoundation.org. ## Code of Conduct [#codeofconduct] -The GraphQL Foundation and the Linux Foundation are dedicated to -providing a harassment-free experience for participants at all of our -events, whether they are held in person or virtually. GraphQLConf is a -working conference intended for professional networking and -collaboration within the open source community. It exists to encourage -the open exchange of ideas and expression and requires an environment -that recognizes the inherent worth of every person and group. While at -GraphQLConf or related ancillary or social events, any participants, -including members, speakers, attendees, volunteers, sponsors, -exhibitors, booth staff and anyone else, should not engage in -harassment in any form. - -This Code of Conduct may be revised at any time by The GraphQL -Foundation or The Linux Foundation and the terms are non-negotiable. -Your registration for or attendance at GraphQL, whether in person or -virtually, indicates your agreement to abide by this policy and its -terms. - -Please read the full [Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct) for the complete policy and terms. +The GraphQL Foundation and the Linux Foundation are dedicated to providing a +harassment-free experience for participants at all of our events, whether they +are held in person or virtually. GraphQLConf is a working conference intended +for professional networking and collaboration within the open source community. +It exists to encourage the open exchange of ideas and expression and requires an +environment that recognizes the inherent worth of every person and group. While +at GraphQLConf or related ancillary or social events, any participants, +including members, speakers, attendees, volunteers, sponsors, exhibitors, booth +staff and anyone else, should not engage in harassment in any form. + +This Code of Conduct may be revised at any time by The GraphQL Foundation or The +Linux Foundation and the terms are non-negotiable. Your registration for or +attendance at GraphQL, whether in person or virtually, indicates your agreement +to abide by this policy and its terms. + +Please read the full +[Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct) for +the complete policy and terms. ## Diversity & Inclusion [#dni] Education and collaboration are vital to the future of the open source -ecosystem, and it is imperative to us that everyone in the community -that wants to participate feels welcome to do so regardless of gender, -gender identity, sexual orientation, disability, race, ethnicity, age, -religion or economic status. Our [code of conduct](#codeofconduct) outlines our expectations -for all those who participate in our community, as well as the -consequences for unacceptable behavior. - -We offer diversity and need based -scholarships and have considered a broad -range of both onsite resources and -emergency resources as well as a -health & safety policy. - -If you have ideas on how we can create a more inclusive event, please -do not hesitate to let us know. Contact Emily Ruf, Senior Event -Manager, at eruf@linuxfoundation.org. +ecosystem, and it is imperative to us that everyone in the community that wants +to participate feels welcome to do so regardless of gender, gender identity, +sexual orientation, disability, race, ethnicity, age, religion or economic +status. Our [code of conduct](#codeofconduct) outlines our expectations for all +those who participate in our community, as well as the consequences for +unacceptable behavior. + +We offer diversity and need based scholarships and have considered a broad range +of both onsite resources and emergency resources as well as a health & safety +policy. + +If you have ideas on how we can create a more inclusive event, please do not +hesitate to let us know. Contact Emily Ruf, Senior Event Manager, at +eruf@linuxfoundation.org. ## CHAOSS D&I Event Badge [#chaoss-event-badge] ![D&I Badging badge state: Gold](https://img.shields.io/badge/D%26I-Gold-yellow?style=flat-square&labelColor=583586&&link=https://github.com/badging/event-diversity-and-inclusion/issues/255/&logo=data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI1MCAyNTAiPgo8cGF0aCBmaWxsPSIjMUM5QkQ2IiBkPSJNOTcuMSw0OS4zYzE4LTYuNywzNy44LTYuOCw1NS45LTAuMmwxNy41LTMwLjJjLTI5LTEyLjMtNjEuOC0xMi4yLTkwLjgsMC4zTDk3LjEsNDkuM3oiLz4KPHBhdGggZmlsbD0iIzZBQzdCOSIgZD0iTTE5NC42LDMyLjhMMTc3LjIsNjNjMTQuOCwxMi4zLDI0LjcsMjkuNSwyNy45LDQ4LjVoMzQuOUMyMzYuMiw4MC4yLDIxOS45LDUxLjcsMTk0LjYsMzIuOHoiLz4KPHBhdGggZmlsbD0iI0JGOUNDOSIgZD0iTTIwNC45LDEzOS40Yy03LjksNDMuOS00OS45LDczLTkzLjgsNjUuMWMtMTMuOC0yLjUtMjYuOC04LjYtMzcuNS0xNy42bC0yNi44LDIyLjQKCWM0Ni42LDQzLjQsMTE5LjUsNDAuOSwxNjIuOS01LjdjMTYuNS0xNy43LDI3LTQwLjIsMzAuMS02NC4ySDIwNC45eiIvPgo8cGF0aCBmaWxsPSIjRDYxRDVGIiBkPSJNNTUuNiwxNjUuNkMzNS45LDEzMS44LDQzLjMsODguOCw3My4xLDYzLjVMNTUuNywzMy4yQzcuNSw2OS44LTQuMiwxMzcuNCwyOC44LDE4OEw1NS42LDE2NS42eiIvPgo8L3N2Zz4K) -Awarded to events in the open source community that fosters healthy -D&I practices. [Learn More](https://chaoss.community/diversity-and-inclusion-badging). +Awarded to events in the open source community that fosters healthy D&I +practices. +[Learn More](https://chaoss.community/diversity-and-inclusion-badging). ## Invoices & Certificates of Attendance [#invoices] ### Registration Invoices -Invoice receipts are downloadable from the confirmation email you -received after registering under the Payment Receipt Information -section. If the downloadable invoice receipt does not meet your needs -or you need to have your confirmation email resent, please submit your -request [here](https://docs.google.com/forms/d/1uxCqF-ieG9QmpU8tl3HqgatHLY9FWhRs7KLpyhZA5KI/edit). -Please include any additional customization you need for your -invoice receipt in the request. +Invoice receipts are downloadable from the confirmation email you received after +registering under the Payment Receipt Information section. If the downloadable +invoice receipt does not meet your needs or you need to have your confirmation +email resent, please submit your request +[here](https://docs.google.com/forms/d/1uxCqF-ieG9QmpU8tl3HqgatHLY9FWhRs7KLpyhZA5KI/edit). +Please include any additional customization you need for your invoice receipt in +the request. ### Certificates of Attendance -To request a Certificate of Attendance, please submit a request [here](https://docs.google.com/forms/d/1RpI8h6AGK2rCl3aIlyEY0D6fU3tsZ5yr1Ba6c3h6p9Y/edit). +To request a Certificate of Attendance, please submit a request +[here](https://docs.google.com/forms/d/1RpI8h6AGK2rCl3aIlyEY0D6fU3tsZ5yr1Ba6c3h6p9Y/edit). **Please note:** We verify attendance through the registration system, and -Certificate of Attendance letters are sent out after the event is -completed. +Certificate of Attendance letters are sent out after the event is completed. ## Refund Policy ### Cancellations -If you must cancel for any reason, please [sign back into your registration](https://cvent.me/4zbxz9), click the “Register/Modify” button and select “Unregister.” If you -need further assistance, email registration@linuxfoundation.org. +If you must cancel for any reason, please +[sign back into your registration](https://cvent.me/4zbxz9), click the +“Register/Modify” button and select “Unregister.” If you need further +assistance, email registration@linuxfoundation.org. -Refunds will only be issued for cancellations received two weeks prior -to the event start date, including bulk ticket request refunds, and -will appear as a credit on the card’s statement 7 – 10 business days -after cancellation. Due to the ongoing pandemic, individual refund -requests due to COVID-19 positive tests will be honored up until the -start date of the event, and must be accompanied by a photo of a -positive COVID-19 test. +Refunds will only be issued for cancellations received two weeks prior to the +event start date, including bulk ticket request refunds, and will appear as a +credit on the card’s statement 7 – 10 business days after cancellation. Due to +the ongoing pandemic, individual refund requests due to COVID-19 positive tests +will be honored up until the start date of the event, and must be accompanied by +a photo of a positive COVID-19 test. -**Please note:** Refunds can only be issued on the card the original -payment was made. +**Please note:** Refunds can only be issued on the card the original payment was +made. ### Substitutions -If you are unable to attend, you may substitute another attendee in -lieu of cancellation. To substitute an attendee, [sign back into your registration](https://cvent.me/4zbxz9) -, click the “Register/Modify”, and select “Transfer Registration” on -your confirmation page. +If you are unable to attend, you may substitute another attendee in lieu of +cancellation. To substitute an attendee, +[sign back into your registration](https://cvent.me/4zbxz9) , click the +“Register/Modify”, and select “Transfer Registration” on your confirmation page. diff --git a/src/app/conf/2024/faq/faq.mdx b/src/app/conf/2024/faq/faq.mdx index e8c5adee33..be4e2423fd 100644 --- a/src/app/conf/2024/faq/faq.mdx +++ b/src/app/conf/2024/faq/faq.mdx @@ -1,190 +1,194 @@ # GraphQLConf FAQ -
{toc.map(({value, id}) => {value})}
+
+ {toc.map(({ value, id }) => ( + + {value} + + ))} +
## Contact Us [#contact] -Answers to many common questions are readily available on this event’s -website. If you cannot find the answer to your question, you are welcome -to contact us by emailing graphql_events@linuxfoundation.org. +Answers to many common questions are readily available on this event’s website. +If you cannot find the answer to your question, you are welcome to contact us by +emailing graphql_events@linuxfoundation.org. ## Confidentiality -We never sell attendee lists or contact information, nor do we authorize -others to do so. If you receive an email claiming to sell an attendee -list for a Linux Foundation event, please forward it to events@linuxfoundation.org. +We never sell attendee lists or contact information, nor do we authorize others +to do so. If you receive an email claiming to sell an attendee list for a Linux +Foundation event, please forward it to events@linuxfoundation.org. ## Code of Conduct [#codeofconduct] -The GraphQL Foundation and the Linux Foundation are dedicated to -providing a harassment-free experience for participants at all of our -events, whether they are held in person or virtually. GraphQLConf is a -working conference intended for professional networking and -collaboration within the open source community. It exists to encourage -the open exchange of ideas and expression and requires an environment -that recognizes the inherent worth of every person and group. While at -GraphQLConf or related ancillary or social events, any participants, -including members, speakers, attendees, volunteers, sponsors, -exhibitors, booth staff and anyone else, should not engage in -harassment in any form. - -This Code of Conduct may be revised at any time by The GraphQL -Foundation or The Linux Foundation and the terms are non-negotiable. -Your registration for or attendance at GraphQL, whether in person or -virtually, indicates your agreement to abide by this policy and its -terms. - -Please read the full [Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct) for the complete policy and terms. +The GraphQL Foundation and the Linux Foundation are dedicated to providing a +harassment-free experience for participants at all of our events, whether they +are held in person or virtually. GraphQLConf is a working conference intended +for professional networking and collaboration within the open source community. +It exists to encourage the open exchange of ideas and expression and requires an +environment that recognizes the inherent worth of every person and group. While +at GraphQLConf or related ancillary or social events, any participants, +including members, speakers, attendees, volunteers, sponsors, exhibitors, booth +staff and anyone else, should not engage in harassment in any form. + +This Code of Conduct may be revised at any time by The GraphQL Foundation or The +Linux Foundation and the terms are non-negotiable. Your registration for or +attendance at GraphQL, whether in person or virtually, indicates your agreement +to abide by this policy and its terms. + +Please read the full +[Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct) for +the complete policy and terms. ## Diversity & Inclusion [#dni] Education and collaboration are vital to the future of the open source -ecosystem, and it is imperative to us that everyone in the community -that wants to participate feels welcome to do so regardless of gender, -gender identity, sexual orientation, disability, race, ethnicity, age, -religion or economic status. Our [code of conduct](#codeofconduct) outlines our expectations -for all those who participate in our community, as well as the -consequences for unacceptable behavior. - -We offer diversity and have considered a broad -range of both [onsite resources](#onsite-resources) and +ecosystem, and it is imperative to us that everyone in the community that wants +to participate feels welcome to do so regardless of gender, gender identity, +sexual orientation, disability, race, ethnicity, age, religion or economic +status. Our [code of conduct](#codeofconduct) outlines our expectations for all +those who participate in our community, as well as the consequences for +unacceptable behavior. + +We offer diversity and have considered a broad range of both +[onsite resources](#onsite-resources) and [emergency resources](#emergency-resources) as well as a [health & safety](#health-and-safety) policy. -If you have ideas on how we can create a more inclusive event, please -do not hesitate to let us know. Contact Emily Ruf, Event Director, at eruf@linuxfoundation.org. +If you have ideas on how we can create a more inclusive event, please do not +hesitate to let us know. Contact Emily Ruf, Event Director, at +eruf@linuxfoundation.org. ## Health & Safety [#health-and-safety] _Updated March 27, 2024_ -_Our community’s well-being is extremely important to us, and -creating a safe, worry-free event is our top priority. We will -adjust our health and safety protocols as needed while updating this -page with information about plans for our attendees onsite. We -continue to look to local municipality guidelines to make the best -and most informed decisions around onsite safety and requirements. -**All in-person attendance requirements are subject to change based on local guidelines.**_ - -{/* - -{

Health Measures

} - -{

COVID-19

} - -Masks are recommended, but not required, to attend this event. There -are no vaccine or testing requirements to attend this event. These are -both subject to change based on local municipality requirements and -any changes in COVID-19. - -We encourage high-risk individuals, and those with family or -colleagues who are at a higher risk of getting COVID-19, to consider -wearing a high-quality mask recommended by health agencies. We also -ask that you respect those around you who choose to wear a mask. A -limited number of masks will be available upon request at Registration -onsite. - -{

Vaccines

} - -We encourage flu shots, COVID-19 vaccination and boosters to reduce -the threat of illness. - -*/} +_Our community’s well-being is extremely important to us, and creating a safe, +worry-free event is our top priority. We will adjust our health and safety +protocols as needed while updating this page with information about plans for +our attendees onsite. We continue to look to local municipality guidelines to +make the best and most informed decisions around onsite safety and requirements. +**All in-person attendance requirements are subject to change based on local +guidelines.**_ {

Onsite Personal Protection

} -- If you feel ill while at the event, please take a COVID-19 self-test and isolate as needed. +- If you feel ill while at the event, please take a COVID-19 self-test and + isolate as needed. - Hand sanitizing stations will be available throughout the event venue. - A limited supply of face masks will be available upon request at Registration. - We respectfully remind all attendees, speakers, sponsors, and staff to: - - Stay home if you experience any cold or flu-like symptoms. - - Wash your hands for at least 20 seconds. - - Stay healthy! Engage in responsible health practices such as avoiding touching eyes/nose/mouth with unwashed hands. -- We’ll be providing a wearable indicator that shows your comfort - level with social distancing. While it's optional to wear, we highly - encourage participants to use it. + - Stay home if you experience any cold or flu-like symptoms. + - Wash your hands for at least 20 seconds. + - Stay healthy! Engage in responsible health practices such as avoiding + touching eyes/nose/mouth with unwashed hands. +- We’ll be providing a wearable indicator that shows your comfort level with + social distancing. While it's optional to wear, we highly encourage + participants to use it. {

Food Allergies

} -The Linux Foundation believes it’s essential to prioritize the safety -and well-being of all attendees, including those with food allergies. +The Linux Foundation believes it’s essential to prioritize the safety and +well-being of all attendees, including those with food allergies. -- We aim to provide a variety of choices to cater to various needs such as vegetarian, vegan, gluten-free, dairy-free, and nut-free. -- All food items will be clearly labeled at the event, indicating the ingredients used and any potential allergens present. +- We aim to provide a variety of choices to cater to various needs such as + vegetarian, vegan, gluten-free, dairy-free, and nut-free. +- All food items will be clearly labeled at the event, indicating the + ingredients used and any potential allergens present. -If you have a food allergy we need to be aware of, please email us at graphql_events@linuxfoundation.org. +If you have a food allergy we need to be aware of, please email us at +graphql_events@linuxfoundation.org. {

Safety Resources & Tips

} -Attendee safety is our top priority. Always exercise common sense and -good judgment when traveling. +Attendee safety is our top priority. Always exercise common sense and good +judgment when traveling. {

General Safety

} - When walking around the city, remember to take off your conference badge. -- Safety in numbers: Exploring the city can be safer when done with a friend or colleague. +- Safety in numbers: Exploring the city can be safer when done with a friend or + colleague. - Walk with purpose and stick to well-lit areas and on main streets. - If alone after dark, use a ride service such as Lyft, Uber or a taxi. - Save the address and phone number of where you’re staying in your phone. - Be aware of your surroundings and keep your eyes up and not on your phone. - If something doesn’t feel right, walk into a business/hotel for help. - Be careful and alert when using a cash machine. -- Carry your purse or wallet safely. Purses should be closed and held in front of your body. Wallets should be carried in a front pants pocket or in an interior jacket pocket. +- Carry your purse or wallet safely. Purses should be closed and held in front + of your body. Wallets should be carried in a front pants pocket or in an + interior jacket pocket. {

When Visiting Any Venue:

} - Know where you are; the venue name, street address or cross street. -- Take a moment to identify at least two exit routes from any building or event and emergency exit signs. -- If an alarm sounds, evacuate immediately. Follow directions from First Responders and venue staff. -- Do not carry any unnecessary valuables with you, or leave personal items unattended. -- Do not leave drinks unattended, or accept open drinks or food products from strangers. +- Take a moment to identify at least two exit routes from any building or event + and emergency exit signs. +- If an alarm sounds, evacuate immediately. Follow directions from First + Responders and venue staff. +- Do not carry any unnecessary valuables with you, or leave personal items + unattended. +- Do not leave drinks unattended, or accept open drinks or food products from + strangers. {

Emergency Evacuations

} -- In the event of an emergency evacuation, make your way quickly and calmly to an emergency exit. Be aware of any hazards or dangers around you and proceed to a safe area. +- In the event of an emergency evacuation, make your way quickly and calmly to + an emergency exit. Be aware of any hazards or dangers around you and proceed + to a safe area. - Follow the advice of venue staff, security personnel and First Responders. -- Do not put yourself in danger by stopping to collect belongings unless directed by First Responders. +- Do not put yourself in danger by stopping to collect belongings unless + directed by First Responders. {

Weapon Policy

} -The Linux Foundation does not allow firearms or other weapons, -regardless of whether they are permitted or not, or whether they are -concealed or not, to be brought into our events. By registering for -the event, you are agreeing that you understand this policy and will -not bring a firearm or other weapons into the event. +The Linux Foundation does not allow firearms or other weapons, regardless of +whether they are permitted or not, or whether they are concealed or not, to be +brought into our events. By registering for the event, you are agreeing that you +understand this policy and will not bring a firearm or other weapons into the +event. ## Invoices & Certificates of Attendance [#invoices] {

Registration Invoices

} -Invoice receipts are downloadable from the confirmation email you -received after registering under the Payment Receipt Information -section. If the downloadable invoice receipt does not meet your needs -or you need to have your confirmation email resent, please submit your -request [here](https://docs.google.com/forms/d/1uxCqF-ieG9QmpU8tl3HqgatHLY9FWhRs7KLpyhZA5KI/edit). -Please include any additional customization you need for your -invoice receipt in the request. +Invoice receipts are downloadable from the confirmation email you received after +registering under the Payment Receipt Information section. If the downloadable +invoice receipt does not meet your needs or you need to have your confirmation +email resent, please submit your request +[here](https://docs.google.com/forms/d/1uxCqF-ieG9QmpU8tl3HqgatHLY9FWhRs7KLpyhZA5KI/edit). +Please include any additional customization you need for your invoice receipt in +the request. {

Certificates of Attendance

} -To request a Certificate of Attendance, please submit a request [here](https://docs.google.com/forms/d/1RpI8h6AGK2rCl3aIlyEY0D6fU3tsZ5yr1Ba6c3h6p9Y/edit). +To request a Certificate of Attendance, please submit a request +[here](https://docs.google.com/forms/d/1RpI8h6AGK2rCl3aIlyEY0D6fU3tsZ5yr1Ba6c3h6p9Y/edit). **Please note:** We verify attendance through the registration system, and -Certificate of Attendance letters are sent out after the event is -completed. - +Certificate of Attendance letters are sent out after the event is completed. ## Refund Policy {

Cancellations

} -If you must cancel for any reason, please click the Unregister button above. If you need further assistance, email registration@linuxfoundation.org. +If you must cancel for any reason, please click the Unregister button above. If +you need further assistance, email registration@linuxfoundation.org. -Refunds will only be issued for cancellations received two weeks prior to the event start date (including bulk ticket request refunds, co-located events, and add-ons), and will appear as a credit on the card’s statement 7 - 10 business days after cancellation. Individual refund requests for late cancellations due to sickness or emergency will be considered on a case by case basis - contact us at registration@linuxfoundation.org. +Refunds will only be issued for cancellations received two weeks prior to the +event start date (including bulk ticket request refunds, co-located events, and +add-ons), and will appear as a credit on the card’s statement 7 - 10 business +days after cancellation. Individual refund requests for late cancellations due +to sickness or emergency will be considered on a case by case basis - contact us +at registration@linuxfoundation.org. -**Please note:** Refunds can only be issued on the card the original payment was made. +**Please note:** Refunds can only be issued on the card the original payment was +made. {

Substitutions

} -If you are unable to attend, you may substitute another attendee in lieu of cancellation. To substitute an attendee, select the Transfer Registration button above. You will be required to provide the attendee's first name, last name, and email address for the registration. - +If you are unable to attend, you may substitute another attendee in lieu of +cancellation. To substitute an attendee, select the Transfer Registration button +above. You will be required to provide the attendee's first name, last name, and +email address for the registration. diff --git a/src/app/conf/2024/partner/index.mdx b/src/app/conf/2024/partner/index.mdx index 41556176e6..23c88d5a8b 100644 --- a/src/app/conf/2024/partner/index.mdx +++ b/src/app/conf/2024/partner/index.mdx @@ -2,27 +2,45 @@ import { Button } from "@/app/conf/_components/button" ## Sponsor GraphQLConf 2024 [#sponsor] -
- - +
+ +
-Contact us at graphqlconf@graphql.org to reserve your sponsorship, ask questions or talk about different options. +Contact us at graphqlconf@graphql.org to reserve your sponsorship, ask questions +or talk about different options. -GraphQLConf is the official GraphQL conference hosted by the GraphQL Foundation. It is a premier event by the community for the community to promote education, adoption, and advancement of GraphQL. +GraphQLConf is the official GraphQL conference hosted by the GraphQL Foundation. +It is a premier event by the community for the community to promote education, +adoption, and advancement of GraphQL. Help make this event one to remember by becoming a sponsor. -GraphQLConf will attract members of the GraphQL community from around the world. Developers, users, architects, and technology leaders from multiple industries will gather in San Francisco to meet, collaborate and build. GraphQLConf 2024 is the flagship event in the GraphQL Foundation’s official event series. - -Investing in GraphQLConf provides the opportunity to build awareness and loyalty with leaders and decision makers in organizations across the GraphQL and open source community. +GraphQLConf will attract members of the GraphQL community from around the world. +Developers, users, architects, and technology leaders from multiple industries +will gather in San Francisco to meet, collaborate and build. GraphQLConf 2024 is +the flagship event in the GraphQL Foundation’s official event series. +Investing in GraphQLConf provides the opportunity to build awareness and loyalty +with leaders and decision makers in organizations across the GraphQL and open +source community. ## Partner with GraphQLConf [#program] -We are pleased to offer a Media and Community Partner Program for -our upcoming GraphQLConf 2024. Our program is designed to provide -benefits to media and community partners, while also ensuring that -our conference is promoted in a positive and appropriate way. +We are pleased to offer a Media and Community Partner Program for our upcoming +GraphQLConf 2024. Our program is designed to provide benefits to media and +community partners, while also ensuring that our conference is promoted in a +positive and appropriate way. {/* prettier-ignore */}
@@ -70,29 +88,31 @@ As a community partner, you will receive the following benefits: ## Obligations for Media and Community Partners [#obligation] -In exchange for these benefits, media and community partners are -expected to fulfill the following obligations: +In exchange for these benefits, media and community partners are expected to +fulfill the following obligations: - Promote the conference through your own media channels or community network -- Include the conference logo and website URL in any promotional materials related to the conference -- Follow conference media and social media guidelines, including not publishing or sharing any defamatory or inappropriate content related to the conference or its attendees +- Include the conference logo and website URL in any promotional materials + related to the conference +- Follow conference media and social media guidelines, including not publishing + or sharing any defamatory or inappropriate content related to the conference + or its attendees - Attend the conference and actively engage with attendees and other partners - Provide feedback and suggestions for improvement of future conferences ## How to Apply [#apply] -To apply to become a media or community partner, please fill out the -application form. Applications will be reviewed on a rolling basis, -and all applicants will be notified of their status within two weeks -of submitting their application. +To apply to become a media or community partner, please fill out the application +form. Applications will be reviewed on a rolling basis, and all applicants will +be notified of their status within two weeks of submitting their application. -Thank you for your interest in partnering with us for GraphQLConf 2024. We look forward to working with you to make our -conference a success! +Thank you for your interest in partnering with us for GraphQLConf 2024. We look +forward to working with you to make our conference a success! -{/* -*/} +> + Fill out the application form + diff --git a/src/app/conf/2024/speak/index.mdx b/src/app/conf/2024/speak/index.mdx index 1bb6b63712..4679ec2989 100644 --- a/src/app/conf/2024/speak/index.mdx +++ b/src/app/conf/2024/speak/index.mdx @@ -4,11 +4,13 @@ import { Button } from "@/app/conf/_components/button" **September 10-12, 2024 | San Francisco, CA** -Putting on an amazing conference depends on great content, which is where you come in! Join -other GraphQL leaders and community members as a presenter by submitting to our Call for -Proposals (CFP) and sharing your experience across a wide range of topics. +Putting on an amazing conference depends on great content, which is where you +come in! Join other GraphQL leaders and community members as a presenter by +submitting to our Call for Proposals (CFP) and sharing your experience across a +wide range of topics. -For any questions regarding the CFP process, please email cfp@linuxfoundation.org. +For any questions regarding the CFP process, please email +cfp@linuxfoundation.org. export const isExpired = new Date() > new Date("2024/05/22 12:00") @@ -20,10 +22,12 @@ export const isExpired = new Date() > new Date("2024/05/22 12:00") {isExpired ? "CFP Closed" : "Submit a Proposal"} -> Please be aware that the Linux Foundation will now be utilizing Sessionize for CFP -> submissions. Sessionize is a cloud-based event content management software designed to be -> intuitive and user-friendly. If you need guidance, please review [how to submit your session for -> an event](https://sessionize.com/playbook/submit-your-session-for-an-event) to see step-by-step instructions and helpful screenshots. +> Please be aware that the Linux Foundation will now be utilizing Sessionize for +> CFP submissions. Sessionize is a cloud-based event content management software +> designed to be intuitive and user-friendly. If you need guidance, please +> review +> [how to submit your session for an event](https://sessionize.com/playbook/submit-your-session-for-an-event) +> to see step-by-step instructions and helpful screenshots. Click through the tabs on this page to access the information. @@ -45,92 +49,128 @@ Click through the tabs on this page to access the information. ## Suggested Topics -{

GraphQL Spec

} -Latest and greatest developments in the GraphQL specification, reference implementation, and related -official specifications such as GraphQL-over-HTTP specification. +{

GraphQL Spec

} Latest and greatest developments in the GraphQL +specification, reference implementation, and related official specifications +such as GraphQL-over-HTTP specification. -{

GraphQL in Production

} -Best practices, real world use cases, spectacular success, spectacular failures, and lessons -learned from production deployments of GraphQL. +{

GraphQL in Production

} Best practices, real world use cases, +spectacular success, spectacular failures, and lessons learned from production +deployments of GraphQL. -{

GraphQL Security

} -Authentication/authorization, security testing, threat models, GraphQL and OWASP Top 10, -exploit analysis and retrospective, full-lifecycle security considerations. +{

GraphQL Security

} Authentication/authorization, security testing, +threat models, GraphQL and OWASP Top 10, exploit analysis and retrospective, +full-lifecycle security considerations. -{

GraphQL Clients

} -Client development (web, mobile, and beyond) with GraphQL, frontend frameworks, GraphQL -IDEs. +{

GraphQL Clients

} Client development (web, mobile, and beyond) with +GraphQL, frontend frameworks, GraphQL IDEs. -{

Backend

} -GraphQL server implementations, data sources for GraphQL resolvers, alternative execution strategies, -and related backend development concerns. +{

Backend

} GraphQL server implementations, data sources for GraphQL +resolvers, alternative execution strategies, and related backend development +concerns. -{

Scaling

} -Everything related to scaling GraphQL: testing, automation, performance, social/organizational -considerations. +{

Scaling

} Everything related to scaling GraphQL: testing, automation, +performance, social/organizational considerations. -{

GraphQL Academia

} -Research papers or studies in academia that involve GraphQL. +{

GraphQL Academia

} Research papers or studies in academia that involve +GraphQL. -{

Emerging Community Trends

} -What’s happening at the vanguard of GraphQL adoption that will help define the future of -GraphQL usage in the community. +{

Emerging Community Trends

} What’s happening at the vanguard of GraphQL +adoption that will help define the future of GraphQL usage in the community. -{

API Platform

} -Integration with platform providers/frameworks, serverless, mesh architectures, AI/ML. +{

API Platform

} Integration with platform providers/frameworks, +serverless, mesh architectures, AI/ML. -{

Federation and Composite Schemas

} -Building a schema from multiple smaller schemas: technologies, experiences, specifications, best -practices, things to avoid. +{

Federation and Composite Schemas

} Building a schema from multiple +smaller schemas: technologies, experiences, specifications, best practices, +things to avoid. -{

Developer Experience

} -The latest and greatest developments in GraphiQL and other GraphQL IDEs, frontend and backend tooling, -editor integrations, AI assistance and more. +{

Developer Experience

} The latest and greatest developments in GraphiQL +and other GraphQL IDEs, frontend and backend tooling, editor integrations, AI +assistance and more. -{

Defies Categorization

} -Have a talk idea that doesn’t fit inside the topics above? Challenge accepted! Wow us with your -awesome talk submission and we’ll work with you to fit it into our track structure. +{

Defies Categorization

} Have a talk idea that doesn’t fit inside the +topics above? Challenge accepted! Wow us with your awesome talk submission and +we’ll work with you to fit it into our track structure. ## Submission Types -- **Session Presentation:** Typically 30-40 minutes in length, 1-2 speakers presenting on a topic -- **Panel Discussion:** Typically 30-40 minutes in length, 3-4 speakers presenting on a topic +- **Session Presentation:** Typically 30-40 minutes in length, 1-2 speakers + presenting on a topic +- **Panel Discussion:** Typically 30-40 minutes in length, 3-4 speakers + presenting on a topic - **Birds of a Feather:** Typically 45 minutes to 1 hour in length - **Lightning Talk:** Typically 5-10 minutes in length - **Workshop:** Typically 1-2 hours in length ## Important Notes -- All speakers are required to adhere to our [Code of Conduct](/conf/2024/faq/#codeofconduct). We also highly recommend that speakers take our online [Inclusive Speaker Orientation Course](https://training.linuxfoundation.org/linux-courses/open-source-compliance-courses/inclusive-speaker-orientation). -- Panel submissions must include the names of all participants in the initial submission to be considered. In an effort to promote speaker diversity, The Linux Foundation does not accept submissions with all-male panels, and speakers must not all be from the same company. -- Complimentary Passes For Speakers – One complimentary pass for the event will be provided for each accepted speaker. -- Avoid sales or marketing pitches and discussing unlicensed or potentially closed-source technologies when preparing your proposal; these talks are almost always rejected due to the fact that they take away from the integrity of our events, and are rarely well-received by conference attendees. -- You are allowed to be listed as a speaker on a maximum of two proposals submitted to the CFP, regardless of the format. If you are listed on more than two, we will contact you to remove yourself from any additional proposals. -- You may only be selected to speak on one panel and one non-panel session per event. +- All speakers are required to adhere to our + [Code of Conduct](/conf/2024/faq/#codeofconduct). We also highly recommend + that speakers take our online + [Inclusive Speaker Orientation Course](https://training.linuxfoundation.org/linux-courses/open-source-compliance-courses/inclusive-speaker-orientation). +- Panel submissions must include the names of all participants in the initial + submission to be considered. In an effort to promote speaker diversity, The + Linux Foundation does not accept submissions with all-male panels, and + speakers must not all be from the same company. +- Complimentary Passes For Speakers – One complimentary pass for the event will + be provided for each accepted speaker. +- Avoid sales or marketing pitches and discussing unlicensed or potentially + closed-source technologies when preparing your proposal; these talks are + almost always rejected due to the fact that they take away from the integrity + of our events, and are rarely well-received by conference attendees. +- You are allowed to be listed as a speaker on a maximum of two proposals + submitted to the CFP, regardless of the format. If you are listed on more than + two, we will contact you to remove yourself from any additional proposals. +- You may only be selected to speak on one panel and one non-panel session per + event. - All accepted speakers are required to submit their slides prior to the event. ## Prepare to Submit -While it is not our intention to provide you with strict instructions on how to prepare your proposal, we hope you will take a moment to review the following guidelines that we have put together to help you prepare the best submission possible. To get started, here are three things that you should consider before submitting your proposal: +While it is not our intention to provide you with strict instructions on how to +prepare your proposal, we hope you will take a moment to review the following +guidelines that we have put together to help you prepare the best submission +possible. To get started, here are three things that you should consider before +submitting your proposal: 1. What are you hoping to get from your presentation? 1. What do you expect the audience to gain from your presentation? 1. How will your presentation help better the ecosystem? -There are plenty of ways to give a presentation about projects and technologies without focusing on company-specific efforts. Remember the things to consider that we mentioned above when writing your proposal and think of ways to make it interesting for attendees while still letting you share your experiences, educate the community about an issue, or generate interest in a project. +There are plenty of ways to give a presentation about projects and technologies +without focusing on company-specific efforts. Remember the things to consider +that we mentioned above when writing your proposal and think of ways to make it +interesting for attendees while still letting you share your experiences, +educate the community about an issue, or generate interest in a project. {

Writing Your Proposal

} -Your abstract title will be the main point of reference for attendees to decide if they want to attend your talk, so choose it carefully. The title should accurately reflect the content of your talk. Speakers are required to adhere to our [Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct). We also highly recommend that speakers take our online [Inclusive Speaker Orientation Course](https://training.linuxfoundation.org/linux-courses/open-source-compliance-courses/inclusive-speaker-orientation). +Your abstract title will be the main point of reference for attendees to decide +if they want to attend your talk, so choose it carefully. The title should +accurately reflect the content of your talk. Speakers are required to adhere to +our [Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct). +We also highly recommend that speakers take our online +[Inclusive Speaker Orientation Course](https://training.linuxfoundation.org/linux-courses/open-source-compliance-courses/inclusive-speaker-orientation). {

How to Give a Great Talk

} -We want to make sure submitters receive resources to help put together a great submission and if accepted, give the best presentation possible. To help with this, we recommend viewing seasoned speaker Dawn Foster’s in-depth talk: [Getting Over Your Imposter Syndrome to Become a Conference Speaker – Dawn Foster, VMware](https://youtu.be/2I5fYBLCfUA). +We want to make sure submitters receive resources to help put together a great +submission and if accepted, give the best presentation possible. To help with +this, we recommend viewing seasoned speaker Dawn Foster’s in-depth talk: +[Getting Over Your Imposter Syndrome to Become a Conference Speaker – Dawn Foster, VMware](https://youtu.be/2I5fYBLCfUA). {

Have More Questions? First Time Submitting? Don’t Feel Intimidated

} -Linux Foundation events are an excellent way to get to know the community and share your ideas and the work that you are doing and we strongly encourage first-time speakers to submit talks for our events. In the instance that you aren’t sure about your abstract, [reach out to us](mailto:cfp@linuxfoundation.org) and we will be more than happy to work with you on your proposal. +Linux Foundation events are an excellent way to get to know the community and +share your ideas and the work that you are doing and we strongly encourage +first-time speakers to submit talks for our events. In the instance that you +aren’t sure about your abstract, +[reach out to us](mailto:cfp@linuxfoundation.org) and we will be more than happy +to work with you on your proposal. ## Code of Conduct -The Linux Foundation is dedicated to providing a harassment-free experience for participants at all of our events. We encourage all submitters to review our complete [Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct). +The Linux Foundation is dedicated to providing a harassment-free experience for +participants at all of our events. We encourage all submitters to review our +complete +[Code of Conduct](https://events.linuxfoundation.org/about/code-of-conduct). diff --git a/src/pages/blog.mdx b/src/pages/blog.mdx index df349e7b40..e48c5ed59e 100644 --- a/src/pages/blog.mdx +++ b/src/pages/blog.mdx @@ -7,10 +7,10 @@ import { clsx } from "clsx" export default function Blog() { const { asPath } = useRouter() - const items = getPagesUnderRoute("/blog").flatMap(item => item.children || item) - const blogs = items.sort( - (a, b) => b.frontMatter.date - a.frontMatter.date, + const items = getPagesUnderRoute("/blog").flatMap( + item => item.children || item ) + const blogs = items.sort((a, b) => b.frontMatter.date - a.frontMatter.date) const currentTag = asPath.startsWith("/blog") ? "" : asPath.replace("/tags/", "").replace(/\/$/, "") @@ -24,7 +24,7 @@ export default function Blog() { }, {}) // const tagList = ( -
+
{Object.entries(tags) .sort((a, b) => b[1] - a[1]) .map(([tag, count]) => ( @@ -32,7 +32,7 @@ export default function Blog() { key={tag} href={currentTag === tag ? "/blog" : `/tags/${tag}`} data-active={currentTag === tag ? "" : undefined} - className={clsx("tag [&[data-active]]:bg-primary capitalize")} + className={clsx("tag capitalize [&[data-active]]:bg-primary")} > {tag.replaceAll("-", " ")} ({count}) @@ -49,39 +49,39 @@ export default function Blog() { href={page.route} className="flex flex-col" > -
+
{page.frontMatter.tags.map(tag => ( {tag.replaceAll("-", " ")} ))}
-
+
{page.frontMatter.title}
-
+
by {page.frontMatter.byline}
- + Read more → - ), + ) ) return ( <> -
-

Blog

+
+

Blog

Categories

{tagList}
-
+
{blogList}
diff --git a/src/pages/blog/2015-09-14-graphql.mdx b/src/pages/blog/2015-09-14-graphql.mdx index 97cd48527c..1f9cfa5b45 100644 --- a/src/pages/blog/2015-09-14-graphql.mdx +++ b/src/pages/blog/2015-09-14-graphql.mdx @@ -5,21 +5,46 @@ date: 2015-09-14 byline: "Lee Byron" --- -When we built Facebook's mobile applications, we needed a data-fetching API powerful enough to describe all of Facebook, yet simple and easy to learn so product developers can focus on building things quickly. We developed GraphQL three years ago to fill this need. Today it powers hundreds of billions of API calls a day. This year we've begun the process of open-sourcing GraphQL by drafting a specification, releasing a reference implementation, and forming a community around it here at [graphql.org](/). +When we built Facebook's mobile applications, we needed a data-fetching API +powerful enough to describe all of Facebook, yet simple and easy to learn so +product developers can focus on building things quickly. We developed GraphQL +three years ago to fill this need. Today it powers hundreds of billions of API +calls a day. This year we've begun the process of open-sourcing GraphQL by +drafting a specification, releasing a reference implementation, and forming a +community around it here at [graphql.org](/). ## Why GraphQL? -Back in 2012, we began an effort to rebuild Facebook's native mobile applications. - -At the time, our iOS and Android apps were thin wrappers around views of our mobile website. While this brought us close to a platonic ideal of the "write one, run anywhere" mobile application, in practice it pushed our mobile-webview apps beyond their limits. As Facebook's mobile apps became more complex, they suffered poor performance and frequently crashed. - -As we transitioned to natively implemented models and views, we found ourselves for the first time needing an API data version of News Feed — which up until that point had only been delivered as HTML. We evaluated our options for delivering News Feed data to our mobile apps, including RESTful server resources and FQL tables (Facebook's SQL-like API). We were frustrated with the differences between the data we wanted to use in our apps and the server queries they required. We don't think of data in terms of resource URLs, secondary keys, or join tables; we think about it in terms of a graph of objects and the models we ultimately use in our apps like NSObjects or JSON. - -There was also a considerable amount of code to write on both the server to prepare the data and on the client to parse it. This frustration inspired a few of us to start the project that ultimately became GraphQL. GraphQL was our opportunity to rethink mobile app data-fetching from the perspective of product designers and developers. It moved the focus of development to the client apps, where designers and developers spend their time and attention. +Back in 2012, we began an effort to rebuild Facebook's native mobile +applications. + +At the time, our iOS and Android apps were thin wrappers around views of our +mobile website. While this brought us close to a platonic ideal of the "write +one, run anywhere" mobile application, in practice it pushed our mobile-webview +apps beyond their limits. As Facebook's mobile apps became more complex, they +suffered poor performance and frequently crashed. + +As we transitioned to natively implemented models and views, we found ourselves +for the first time needing an API data version of News Feed — which up until +that point had only been delivered as HTML. We evaluated our options for +delivering News Feed data to our mobile apps, including RESTful server resources +and FQL tables (Facebook's SQL-like API). We were frustrated with the +differences between the data we wanted to use in our apps and the server queries +they required. We don't think of data in terms of resource URLs, secondary keys, +or join tables; we think about it in terms of a graph of objects and the models +we ultimately use in our apps like NSObjects or JSON. + +There was also a considerable amount of code to write on both the server to +prepare the data and on the client to parse it. This frustration inspired a few +of us to start the project that ultimately became GraphQL. GraphQL was our +opportunity to rethink mobile app data-fetching from the perspective of product +designers and developers. It moved the focus of development to the client apps, +where designers and developers spend their time and attention. ## What is GraphQL? -A GraphQL query is a string that is sent to a server to be interpreted and fulfilled, which then returns JSON back to the client. +A GraphQL query is a string that is sent to a server to be interpreted and +fulfilled, which then returns JSON back to the client. ```graphql # { "graphiql": true, "schema": "Users" } @@ -44,15 +69,40 @@ A GraphQL query is a string that is sent to a server to be interpreted and fulfi } ``` -**Defines a data shape:** The first thing you'll notice is that GraphQL queries mirror their response. This makes it easy to predict the shape of the data returned from a query, as well as to write a query if you know the data your app needs. More important, this makes GraphQL really easy to learn and use. GraphQL is unapologetically driven by the data requirements of products and of the designers and developers who build them. - -**Hierarchical:** Another important aspect of GraphQL is its hierarchical nature. GraphQL naturally follows relationships between objects, where a RESTful service may require multiple round-trips (resource-intensive on mobile networks) or a complex join statement in SQL. This data hierarchy pairs well with graph-structured data stores and ultimately with the hierarchical user interfaces it's used within. - -**Strongly typed:** Each level of a GraphQL query corresponds to a particular type, and each type describes a set of available fields. Similar to SQL, this allows GraphQL to provide descriptive error messages before executing a query. It also plays well with the strongly typed native environments of Obj-C and Java. - -**Protocol, not storage:** Each GraphQL field on the server is backed by a function - code linking to your application layer. While we were building GraphQL to support News Feed, we already had a sophisticated feed ranking and storage model, along with existing databases and business logic. GraphQL had to leverage all this existing work to be useful, and so does not dictate or provide any backing storage. Instead, GraphQL takes advantage of your existing code by exposing your application layer, not your storage layer. - -**Introspective:** A GraphQL server can be queried for the types it supports. This creates a powerful platform for tools and client software to build atop this information like code generation in statically typed languages, our application framework, Relay, or IDEs like GraphiQL (pictured below). GraphiQL helps developers learn and explore an API quickly without grepping the codebase or wrangling with cURL. +**Defines a data shape:** The first thing you'll notice is that GraphQL queries +mirror their response. This makes it easy to predict the shape of the data +returned from a query, as well as to write a query if you know the data your app +needs. More important, this makes GraphQL really easy to learn and use. GraphQL +is unapologetically driven by the data requirements of products and of the +designers and developers who build them. + +**Hierarchical:** Another important aspect of GraphQL is its hierarchical +nature. GraphQL naturally follows relationships between objects, where a RESTful +service may require multiple round-trips (resource-intensive on mobile networks) +or a complex join statement in SQL. This data hierarchy pairs well with +graph-structured data stores and ultimately with the hierarchical user +interfaces it's used within. + +**Strongly typed:** Each level of a GraphQL query corresponds to a particular +type, and each type describes a set of available fields. Similar to SQL, this +allows GraphQL to provide descriptive error messages before executing a query. +It also plays well with the strongly typed native environments of Obj-C and +Java. + +**Protocol, not storage:** Each GraphQL field on the server is backed by a +function - code linking to your application layer. While we were building +GraphQL to support News Feed, we already had a sophisticated feed ranking and +storage model, along with existing databases and business logic. GraphQL had to +leverage all this existing work to be useful, and so does not dictate or provide +any backing storage. Instead, GraphQL takes advantage of your existing code by +exposing your application layer, not your storage layer. + +**Introspective:** A GraphQL server can be queried for the types it supports. +This creates a powerful platform for tools and client software to build atop +this information like code generation in statically typed languages, our +application framework, Relay, or IDEs like GraphiQL (pictured below). GraphiQL +helps developers learn and explore an API quickly without grepping the codebase +or wrangling with cURL. ```graphql # { "graphiql": true, "schema": "Users" } @@ -69,15 +119,53 @@ A GraphQL query is a string that is sent to a server to be interpreted and fulfi } ``` -**Version free:** The shape of the returned data is determined entirely by the client's query, so servers become simpler and easy to generalize. When you're adding new product features, additional fields can be added to the server, leaving existing clients unaffected. When you're sunsetting older features, the corresponding server fields can be deprecated but continue to function. This gradual, backward-compatible process removes the need for an incrementing version number. We still support three years of released Facebook applications on a single version of our GraphQL API. - -With GraphQL, we were able to build full-featured native News Feed on iOS in 2012, and on Android shortly after. Since then, GraphQL has become the primary way we build our mobile apps and the servers that power them. More than three years later, GraphQL powers almost all data-fetching in our mobile applications, serving millions of requests per second from nearly 1,000 shipped application versions. - -When we built GraphQL in 2012 we had no idea how important it would become to how we build things at Facebook and didn't anticipate its value beyond Facebook. However, earlier this year we announced Relay, our application framework for the web and React Native built atop GraphQL. The community excitement for Relay inspired us to revisit GraphQL to evaluate every detail, make improvements, fix inconsistencies, and write a specification describing GraphQL and how it works. - -Two months ago, we [made our progress public](https://youtube.com/watch?v=WQLzZf34FJ8) and released a working draft of the [GraphQL spec](https://spec.graphql.org) and a reference implementation: [GraphQL.js](https://github.com/graphql/graphql-js). Since then, a community has started to form around GraphQL, and versions of the GraphQL runtime are being [built in many languages](https://github.com/chentsulin/awesome-graphql), including Go, Ruby, Scala, Java, .Net, and Python. We've also begun to share some of the tools we use internally, like [GraphiQL](https://github.com/graphql/graphiql), an in-browser IDE, documentation browser, and query runner. GraphQL has also seen production usage outside Facebook, in a project for the [_Financial Times_](https://youtube.com/watch?v=S0s935RKKB4) by consultancy [Red Badger](http://red-badger.com). - -“GraphQL makes orchestrating data fetching so much simpler, and it pretty much functions as a perfect isolation point between the front end and the back end” -— Viktor Charypar, software engineer at Red Badger - -While GraphQL is an established part of building products at Facebook, its use beyond Facebook is just beginning. Try out [GraphiQL](http://graphql-swapi.parseapp.com/graphiql) and help provide feedback on our [specification](https://github.com/facebook/graphql). We think GraphQL can greatly simplify data needs for both client product developers and server-side engineers, regardless of what languages you're using in either environment, and we're excited to continue to improve GraphQL, help a community grow around it, and see what we can build together. +**Version free:** The shape of the returned data is determined entirely by the +client's query, so servers become simpler and easy to generalize. When you're +adding new product features, additional fields can be added to the server, +leaving existing clients unaffected. When you're sunsetting older features, the +corresponding server fields can be deprecated but continue to function. This +gradual, backward-compatible process removes the need for an incrementing +version number. We still support three years of released Facebook applications +on a single version of our GraphQL API. + +With GraphQL, we were able to build full-featured native News Feed on iOS in +2012, and on Android shortly after. Since then, GraphQL has become the primary +way we build our mobile apps and the servers that power them. More than three +years later, GraphQL powers almost all data-fetching in our mobile applications, +serving millions of requests per second from nearly 1,000 shipped application +versions. + +When we built GraphQL in 2012 we had no idea how important it would become to +how we build things at Facebook and didn't anticipate its value beyond Facebook. +However, earlier this year we announced Relay, our application framework for the +web and React Native built atop GraphQL. The community excitement for Relay +inspired us to revisit GraphQL to evaluate every detail, make improvements, fix +inconsistencies, and write a specification describing GraphQL and how it works. + +Two months ago, we +[made our progress public](https://youtube.com/watch?v=WQLzZf34FJ8) and released +a working draft of the [GraphQL spec](https://spec.graphql.org) and a reference +implementation: [GraphQL.js](https://github.com/graphql/graphql-js). Since then, +a community has started to form around GraphQL, and versions of the GraphQL +runtime are being +[built in many languages](https://github.com/chentsulin/awesome-graphql), +including Go, Ruby, Scala, Java, .Net, and Python. We've also begun to share +some of the tools we use internally, like +[GraphiQL](https://github.com/graphql/graphiql), an in-browser IDE, +documentation browser, and query runner. GraphQL has also seen production usage +outside Facebook, in a project for the +[_Financial Times_](https://youtube.com/watch?v=S0s935RKKB4) by consultancy +[Red Badger](http://red-badger.com). + +“GraphQL makes orchestrating data fetching so much simpler, and it pretty much +functions as a perfect isolation point between the front end and the back end” — +Viktor Charypar, software engineer at Red Badger + +While GraphQL is an established part of building products at Facebook, its use +beyond Facebook is just beginning. Try out +[GraphiQL](http://graphql-swapi.parseapp.com/graphiql) and help provide feedback +on our [specification](https://github.com/facebook/graphql). We think GraphQL +can greatly simplify data needs for both client product developers and +server-side engineers, regardless of what languages you're using in either +environment, and we're excited to continue to improve GraphQL, help a community +grow around it, and see what we can build together. diff --git a/src/pages/blog/2015-10-16-subscriptions.mdx b/src/pages/blog/2015-10-16-subscriptions.mdx index 5a0318ebd7..f37cbff8e2 100644 --- a/src/pages/blog/2015-10-16-subscriptions.mdx +++ b/src/pages/blog/2015-10-16-subscriptions.mdx @@ -5,39 +5,67 @@ date: 2015-10-16 byline: Dan Schafer and Laney Kuenzel --- -When we announced and open-sourced GraphQL and Relay this year, we described how they can be used to perform reads with queries, and to perform writes with mutations. However, oftentimes clients want to get pushed updates from the server when data they care about changes. To support that, we’ve introduced a third operation into the GraphQL specification: subscription. +When we announced and open-sourced GraphQL and Relay this year, we described how +they can be used to perform reads with queries, and to perform writes with +mutations. However, oftentimes clients want to get pushed updates from the +server when data they care about changes. To support that, we’ve introduced a +third operation into the GraphQL specification: subscription. ## Event-based subscriptions -The approach that we’ve taken to subscriptions parallels that of mutations; just as the list of mutations that the server supports describes all of the actions that a client can take, the list of subscriptions that the server supports describes all of the events that it can subscribe to. Just as a client can tell the server what data to refetch after it performs a mutation with a GraphQL selection, the client can tell the server what data it wants to be pushed with the subscription with a GraphQL selection. +The approach that we’ve taken to subscriptions parallels that of mutations; just +as the list of mutations that the server supports describes all of the actions +that a client can take, the list of subscriptions that the server supports +describes all of the events that it can subscribe to. Just as a client can tell +the server what data to refetch after it performs a mutation with a GraphQL +selection, the client can tell the server what data it wants to be pushed with +the subscription with a GraphQL selection. -For example, in the Facebook schema, we have a mutation field named `storyLike`, that clients can use to like a post. The client might want to refetch the like count, as well as the like sentence (“Dan and 3 others like this”. We do this translation on the server because of the complexity of that translation in various languages). To do so, they would issue the following mutation: +For example, in the Facebook schema, we have a mutation field named `storyLike`, +that clients can use to like a post. The client might want to refetch the like +count, as well as the like sentence (“Dan and 3 others like this”. We do this +translation on the server because of the complexity of that translation in +various languages). To do so, they would issue the following mutation: ```graphql mutation StoryLikeMutation($input: StoryLikeInput) { storyLike(input: $input) { story { - likers { count } - likeSentence { text } + likers { + count + } + likeSentence { + text + } } } } ``` -But when you’re looking at a post, you also want to get pushed an update whenever someone else likes the post! That’s where subscriptions come in; the Facebook schema has a subscription field named `storyLikeSubscribe` that allows the client to get pushed data anytime someone likes or unlikes that story! The client would create a subscription like this: +But when you’re looking at a post, you also want to get pushed an update +whenever someone else likes the post! That’s where subscriptions come in; the +Facebook schema has a subscription field named `storyLikeSubscribe` that allows +the client to get pushed data anytime someone likes or unlikes that story! The +client would create a subscription like this: ```graphql subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { storyLikeSubscribe(input: $input) { story { - likers { count } - likeSentence { text } + likers { + count + } + likeSentence { + text + } } } } ``` -The client would then send this subscription to the server, along with the value for the `$input` variable, which would contain information like the story ID to which we are subscribing: +The client would then send this subscription to the server, along with the value +for the `$input` variable, which would contain information like the story ID to +which we are subscribing: ```graphql input StoryLikeSubscribeInput { @@ -46,21 +74,33 @@ input StoryLikeSubscribeInput { } ``` -At Facebook, we send this query to the server at build time to generate a unique ID for it, then subscribe to a special MQTT topic with the subscription ID in it, but many different subscription mechanisms could be used here. +At Facebook, we send this query to the server at build time to generate a unique +ID for it, then subscribe to a special MQTT topic with the subscription ID in +it, but many different subscription mechanisms could be used here. -On the server, we then trigger this subscription every time someone likes a post. If all of our clients were using GraphQL, we could put this hook in the GraphQL mutation; since we have non-GraphQL clients as well, we put the hook in a layer below the GraphQL mutation to ensure it always fires. +On the server, we then trigger this subscription every time someone likes a +post. If all of our clients were using GraphQL, we could put this hook in the +GraphQL mutation; since we have non-GraphQL clients as well, we put the hook in +a layer below the GraphQL mutation to ensure it always fires. ## Why not Live Queries? -Notably, this approach requires the client to subscribe to events that it cares about. Another approach is to have the client subscribe to a query, and ask for updates every time the result of that query changes. Why didn’t we take that approach? +Notably, this approach requires the client to subscribe to events that it cares +about. Another approach is to have the client subscribe to a query, and ask for +updates every time the result of that query changes. Why didn’t we take that +approach? Let’s look back at the data we wanted to refetch for the story: ```graphql fragment StoryLikeData on Story { story { - likers { count } - likeSentence { text } + likers { + count + } + likeSentence { + text + } } } ``` @@ -69,20 +109,49 @@ What events could trigger that a change to the data fetched in that fragment? - Someone likes the post. - Someone unlikes the post. -- Someone who had liked the post deactivates their account (changes the like count down one, changes the like sentence to decrement the translated count). -- Someone who had liked the post reactivates their account (changes the like count up one, changes the like sentence to increment the translated count). -- Someone who had liked the post blocks you (cannot show them in the like sentence). -- Someone who had liked the post changes their name (need to update the text of the like sentence). -- Our internal ranking model for the ordering of names in the like sentence updates, and we should be listing a different person first (want to update the text of the like sentence). - -And that’s just the tip of the iceberg in terms of events; each of those events also becomes tricky when there are thousands of people subscribed, and millions of people who liked the post. Implementing live queries for this set of data proved to be immensely complicated. - -When building event-based subscriptions, the problem of determining what should trigger an event is easy, since the event defines that explicitly. It also proved fairly straight-forward to implement atop existing message queue systems. For live queries, though, this appeared much harder. The value of our fields is determined by the result of their resolve function, and figuring out all of the things that could alter the result of that function was difficult. We could in theory have polled on the server to implement this, but that had efficiency and timeliness issues. Based on this, we decided to invest in the event-based subscription approach. +- Someone who had liked the post deactivates their account (changes the like + count down one, changes the like sentence to decrement the translated count). +- Someone who had liked the post reactivates their account (changes the like + count up one, changes the like sentence to increment the translated count). +- Someone who had liked the post blocks you (cannot show them in the like + sentence). +- Someone who had liked the post changes their name (need to update the text of + the like sentence). +- Our internal ranking model for the ordering of names in the like sentence + updates, and we should be listing a different person first (want to update the + text of the like sentence). + +And that’s just the tip of the iceberg in terms of events; each of those events +also becomes tricky when there are thousands of people subscribed, and millions +of people who liked the post. Implementing live queries for this set of data +proved to be immensely complicated. + +When building event-based subscriptions, the problem of determining what should +trigger an event is easy, since the event defines that explicitly. It also +proved fairly straight-forward to implement atop existing message queue systems. +For live queries, though, this appeared much harder. The value of our fields is +determined by the result of their resolve function, and figuring out all of the +things that could alter the result of that function was difficult. We could in +theory have polled on the server to implement this, but that had efficiency and +timeliness issues. Based on this, we decided to invest in the event-based +subscription approach. ## What’s next? -We’re actively building out the event-based subscription approach described above. We’ve built out live liking and commenting features on our iOS and Android apps using that approach, and are continuing to flesh out its functionality and API. While its current implementation at Facebook is coupled to Facebook’s infrastructure, we’re certainly looking forward to open sourcing our progress here as soon as we can. - -Because our backend and schema don’t offer easy support for live queries, we don’t have any plans to develop them at Facebook. At the same time, it’s clear that there are backends and schemas for which live queries are feasible, and that they offer a lot of value in those situations. The discussion in the community on this topic has been fantastic, and we’re excited to see what kind of live query proposals emerge from it! - -Subscriptions create a ton of possibilities for creating truly dynamic applications. We’re excited to continue developing GraphQL and Relay with the help of the community to enable these possibilities. +We’re actively building out the event-based subscription approach described +above. We’ve built out live liking and commenting features on our iOS and +Android apps using that approach, and are continuing to flesh out its +functionality and API. While its current implementation at Facebook is coupled +to Facebook’s infrastructure, we’re certainly looking forward to open sourcing +our progress here as soon as we can. + +Because our backend and schema don’t offer easy support for live queries, we +don’t have any plans to develop them at Facebook. At the same time, it’s clear +that there are backends and schemas for which live queries are feasible, and +that they offer a lot of value in those situations. The discussion in the +community on this topic has been fantastic, and we’re excited to see what kind +of live query proposals emerge from it! + +Subscriptions create a ton of possibilities for creating truly dynamic +applications. We’re excited to continue developing GraphQL and Relay with the +help of the community to enable these possibilities. diff --git a/src/pages/blog/2016-04-19-mocking.mdx b/src/pages/blog/2016-04-19-mocking.mdx index f77a19880b..2801432c57 100644 --- a/src/pages/blog/2016-04-19-mocking.mdx +++ b/src/pages/blog/2016-04-19-mocking.mdx @@ -6,40 +6,86 @@ byline: "Jonas Helfer" guestBio: engineer at Meteor working on Apollo --- -Do you think mocking your backend is always a tedious task? If you do, reading this post might change your mind… - -Mocking is the practice of creating a fake version of a component, so that you can develop and test other parts of your application independently. Mocking your backend is a great way to quickly build a prototype of your frontend, and it lets you test your frontend without starting up any servers. API mocking is so useful that a [quick Google search](https://www.google.com/?ion=1&espv=2#q=mock+rest+api) will turn up dozens of expensive products and services that promise to help you. - -Sadly, I think none of the solutions out there make it as easy as it should be. As it turns out, that’s because they’ve been trying to do it with the wrong technology! - -> Editor’s note : The concepts in this post are accurate, but some the code samples don’t demonstrate new usage patterns. After reading, consult the [graphql-tools docs](http://dev.apollodata.com/tools/graphql-tools/mocking.html) to see how to use mocking today. +Do you think mocking your backend is always a tedious task? If you do, reading +this post might change your mind… + +Mocking is the practice of creating a fake version of a component, so that you +can develop and test other parts of your application independently. Mocking your +backend is a great way to quickly build a prototype of your frontend, and it +lets you test your frontend without starting up any servers. API mocking is so +useful that a +[quick Google search](https://www.google.com/?ion=1&espv=2#q=mock+rest+api) will +turn up dozens of expensive products and services that promise to help you. + +Sadly, I think none of the solutions out there make it as easy as it should be. +As it turns out, that’s because they’ve been trying to do it with the wrong +technology! + +> Editor’s note : The concepts in this post are accurate, but some the code +> samples don’t demonstrate new usage patterns. After reading, consult the +> [graphql-tools docs](http://dev.apollodata.com/tools/graphql-tools/mocking.html) +> to see how to use mocking today. ## Why mock? Mocking the data a backend would return is very useful for two main reasons: -1. It lets you start developing a frontend feature when you don’t have a working backend for it yet. This is critical for projects where the frontend and backend components are often developed in parallel. -2. It lets you run tests locally without connecting to a real backend, which is much faster and safer. As your codebase grows and your app becomes more complex, starting up all of the server infrastructure just to run some tests isn’t feasible. +1. It lets you start developing a frontend feature when you don’t have a working + backend for it yet. This is critical for projects where the frontend and + backend components are often developed in parallel. +2. It lets you run tests locally without connecting to a real backend, which is + much faster and safer. As your codebase grows and your app becomes more + complex, starting up all of the server infrastructure just to run some tests + isn’t feasible. -If mocking your backend API has such clear benefits, why doesn’t everyone do it? I think it's because mocking often seems like too much trouble to be worth it. +If mocking your backend API has such clear benefits, why doesn’t everyone do it? +I think it's because mocking often seems like too much trouble to be worth it. ## Why is mocking backends hard? -Let’s say your backend is some REST API that is called over HTTP from the browser. You have someone working on the backend, and someone else working on the frontend. The backend code actually determines the shape of the data returned for each REST endpoint, but mocking has to be done in the frontend code. That means the mocking code will break every time the backend changes, unless both are changed at the same time. What’s worse, if you’re doing your frontend testing against a mock backend that is not up to date with your backend, your tests may pass, but your actual frontend won’t work. - -Rather than having to keep more dependencies up to date, the easy option is to just not mock the REST API, or have the backend be in charge of mocking itself, just so it’s all in one place. That may be easier, but it will also slow you down. - -The other reason I often hear for why people don’t mock the backend in their project is because it takes time to set up: first you have to include extra logic in your data fetching layer that lets you turn mocking on and off, and second you have to actually describe what that mock data should look like. For any non-trivial API that requires a lot of tedious work. - -Both of these reasons for why mocking backends is hard are actually due to the same underlying reason: there is no standard REST API description in machine-consumable format and contains all the information necessary for mocking and can be used by both the backend and the frontend. There are some API description standards, like Swagger, but they don’t contain all of the information you need, and can be cumbersome to write and maintain. Unless you want to pay for a service or a product — and maybe even then — mocking is a lot of work. - -Actually, I should say mocking used to be a lot of work, because a new technology is changing the way we think of APIs: GraphQL. +Let’s say your backend is some REST API that is called over HTTP from the +browser. You have someone working on the backend, and someone else working on +the frontend. The backend code actually determines the shape of the data +returned for each REST endpoint, but mocking has to be done in the frontend +code. That means the mocking code will break every time the backend changes, +unless both are changed at the same time. What’s worse, if you’re doing your +frontend testing against a mock backend that is not up to date with your +backend, your tests may pass, but your actual frontend won’t work. + +Rather than having to keep more dependencies up to date, the easy option is to +just not mock the REST API, or have the backend be in charge of mocking itself, +just so it’s all in one place. That may be easier, but it will also slow you +down. + +The other reason I often hear for why people don’t mock the backend in their +project is because it takes time to set up: first you have to include extra +logic in your data fetching layer that lets you turn mocking on and off, and +second you have to actually describe what that mock data should look like. For +any non-trivial API that requires a lot of tedious work. + +Both of these reasons for why mocking backends is hard are actually due to the +same underlying reason: there is no standard REST API description in +machine-consumable format and contains all the information necessary for mocking +and can be used by both the backend and the frontend. There are some API +description standards, like Swagger, but they don’t contain all of the +information you need, and can be cumbersome to write and maintain. Unless you +want to pay for a service or a product — and maybe even then — mocking is a lot +of work. + +Actually, I should say mocking used to be a lot of work, because a new +technology is changing the way we think of APIs: GraphQL. ## Mocking is easy with a type system! -GraphQL makes mocking easy, because every GraphQL backend comes with a static type system. The types can be shared between your backend and your frontend, and they contain all of the information necessary to make mocking incredibly fast and convenient. With GraphQL, there is no excuse to not mock your backend for development or testing. +GraphQL makes mocking easy, because every GraphQL backend comes with a static +type system. The types can be shared between your backend and your frontend, and +they contain all of the information necessary to make mocking incredibly fast +and convenient. With GraphQL, there is no excuse to not mock your backend for +development or testing. -Here’s how easy it is to create a mocked backend that will accept any valid GraphQL query with the GraphQL mocking tool we are building as part of our new [GraphQL server toolkit](https://github.com/apollostack/graphql-tools): +Here’s how easy it is to create a mocked backend that will accept any valid +GraphQL query with the GraphQL mocking tool we are building as part of our new +[GraphQL server toolkit](https://github.com/apollostack/graphql-tools): ```js // > npm install graphql-tools @@ -65,17 +111,34 @@ myMockServer.query(`{ // } ``` -Every GraphQL server needs a schema, so it’s not extra code you need to write just for mocking. And the query is the one your component already uses for fetching data, so that’s also not code you write just for mocking. Not counting the import statement, it only took us one line of code to mock the entire backend! +Every GraphQL server needs a schema, so it’s not extra code you need to write +just for mocking. And the query is the one your component already uses for +fetching data, so that’s also not code you write just for mocking. Not counting +the import statement, it only took us one line of code to mock the entire +backend! -Put that in contrast to most REST APIs out there, where mocking means parsing a URL and returning data in a custom shape for each endpoint. It takes dozens of lines to mock a single endpoint that returns some realistic-looking data. With GraphQL, the shape is encoded in the query, and together with the schema we have enough information to mock the server with a single line of code. +Put that in contrast to most REST APIs out there, where mocking means parsing a +URL and returning data in a custom shape for each endpoint. It takes dozens of +lines to mock a single endpoint that returns some realistic-looking data. With +GraphQL, the shape is encoded in the query, and together with the schema we have +enough information to mock the server with a single line of code. -Did I mention that this one line is all you need to return mock data for any valid GraphQL query you could send? Not just some valid query, any valid query! Pretty cool, right? +Did I mention that this one line is all you need to return mock data for any +valid GraphQL query you could send? Not just some valid query, any valid query! +Pretty cool, right? ## Customizing mock data -In the example above, the mock server will return completely random IDs and strings every time you query it. When you’ve just started building your app and only want to see what your UI code looks like in different states, that’s probably good enough, but as you start to fine-tune your layout, or want to use the mock server to test your component’s logic, you’ll probably need more realistic data. +In the example above, the mock server will return completely random IDs and +strings every time you query it. When you’ve just started building your app and +only want to see what your UI code looks like in different states, that’s +probably good enough, but as you start to fine-tune your layout, or want to use +the mock server to test your component’s logic, you’ll probably need more +realistic data. -Luckily, this takes only a little more effort: customization of mock data is really where the Apollo mocking tool shines, because it lets you customize virtually everything about the mock data that it returns. +Luckily, this takes only a little more effort: customization of mock data is +really where the Apollo mocking tool shines, because it lets you customize +virtually everything about the mock data that it returns. It lets you do all of the following and more: @@ -84,14 +147,14 @@ It lets you do all of the following and more: mockServer(schema, { Int: () => 6, Float: () => 22.1, - String: () => 'Hello' + String: () => "Hello" }) // customize mocking per field in the schema (i.e. for Person.name and Person.age) mockServer(schema, { Person: () => ({ name: casual.name, - age: () => casual.integer(0,120) + age: () => casual.integer(0, 120) }) }) @@ -99,7 +162,7 @@ mockServer(schema, { mockServer(schema, { Person: () => ({ // a list of length between 2 and 6 - friends: () => new MockList([2,6]), + friends: () => new MockList([2, 6]), // a list of three lists of two items: [[1, 1], [2, 2], [3, 3]] listOfLists: () => new MockList(3, () => new MockList(2)) }) @@ -116,11 +179,21 @@ mockServer(schema, { // You can also disable mocking for specific fields, pass through to the backend, etc. ``` -For each type and each field you can provide a function that will be called on to generate mock data. Mock functions on fields have precedence over mock functions on types, but they work together really nicely: The field mock functions only need to describe the properties of the objects that matter to them, type mock functions will fill in the rest. +For each type and each field you can provide a function that will be called on +to generate mock data. Mock functions on fields have precedence over mock +functions on types, but they work together really nicely: The field mock +functions only need to describe the properties of the objects that matter to +them, type mock functions will fill in the rest. -The mock functions are actually just GraphQL resolve functions in disguise. What that means is that your mocking can do anything that you could do inside a GraphQL resolve function. If you wanted, you could write your entire backend with it. I’m not saying you should, but you could. +The mock functions are actually just GraphQL resolve functions in disguise. What +that means is that your mocking can do anything that you could do inside a +GraphQL resolve function. If you wanted, you could write your entire backend +with it. I’m not saying you should, but you could. -I think the real power of this tool is that while it allows almost arbitrarily complex customization, you can get started really quickly and increase the sophistication of your mocks in tiny steps whenever you need it. Each step is so simple that it will feel like a breeze. +I think the real power of this tool is that while it allows almost arbitrarily +complex customization, you can get started really quickly and increase the +sophistication of your mocks in tiny steps whenever you need it. Each step is so +simple that it will feel like a breeze. But enough talking, here’s a complete example: @@ -163,14 +236,14 @@ const schema = ` // will be used to resolve the field if the query requests it. const server = mockServer(schema, { RootQuery: () => ({ - user: (o, { id }) => ({ id }), + user: (o, { id }) => ({ id }) }), List: () => ({ name: () => casual.word, - tasks: () => new MockList(4, (o, { completed }) => ({ completed })), + tasks: () => new MockList(4, (o, { completed }) => ({ completed })) }), Task: () => ({ text: casual.words(10) }), - User: () => ({ name: casual.name }), + User: () => ({ name: casual.name }) }) mockServer.query(` @@ -199,12 +272,21 @@ query tasksForUser{ ## Live demo + try it yourself -To see the example in action and see what output it generates, head over to the [live demo](https://launchpad.graphql.com/98lq7vz8r) try running some queries! +To see the example in action and see what output it generates, head over to the +[live demo](https://launchpad.graphql.com/98lq7vz8r) try running some queries! -If you want to fiddle around with the example, just click the "Download" button in the Launchpad UI. If you’re curious about how it works or want to see what other tools we’re building for GraphQL, then head over to [apollostack/graphql-tools](https://github.com/apollostack/graphql-tools). +If you want to fiddle around with the example, just click the "Download" button +in the Launchpad UI. If you’re curious about how it works or want to see what +other tools we’re building for GraphQL, then head over to +[apollostack/graphql-tools](https://github.com/apollostack/graphql-tools). -Pretty cool, right? All of that becomes possible by using a type system. And that’s only just the beginning — we‘re working on bridging the gap between mocking and the real thing so that your mock server can gradually turn into your real server as you add more functionality to it. +Pretty cool, right? All of that becomes possible by using a type system. And +that’s only just the beginning — we‘re working on bridging the gap between +mocking and the real thing so that your mock server can gradually turn into your +real server as you add more functionality to it. --- -_This post was originally published on [the Apollo Blog](https://medium.com/apollo-stack). We publish one or two posts every week, about the stuff we’re working on and thinking about._ +_This post was originally published on +[the Apollo Blog](https://medium.com/apollo-stack). We publish one or two posts +every week, about the stuff we’re working on and thinking about._ diff --git a/src/pages/blog/2016-05-02-rest-api-graphql-wrapper.mdx b/src/pages/blog/2016-05-02-rest-api-graphql-wrapper.mdx index 19c11fd5c9..f5c754d428 100644 --- a/src/pages/blog/2016-05-02-rest-api-graphql-wrapper.mdx +++ b/src/pages/blog/2016-05-02-rest-api-graphql-wrapper.mdx @@ -5,19 +5,33 @@ date: 2016-05-05 byline: "Steven Luscher" --- -Time and time again I hear the same aspiration from front-end web and mobile developers: they're eager to reap the developer efficiency gains offered by new technologies like Relay and GraphQL, but they have years of momentum behind their existing REST API. Without data that clearly demonstrates the benefits of switching, they find it hard to justify an additional investment in GraphQL infrastructure. +Time and time again I hear the same aspiration from front-end web and mobile +developers: they're eager to reap the developer efficiency gains offered by new +technologies like Relay and GraphQL, but they have years of momentum behind +their existing REST API. Without data that clearly demonstrates the benefits of +switching, they find it hard to justify an additional investment in GraphQL +infrastructure. -In this post I will outline a rapid, low-investment method that you can use to stand up a GraphQL endpoint atop an existing REST API, using JavaScript alone. No backend developers will be harmed during the making of this blog post. +In this post I will outline a rapid, low-investment method that you can use to +stand up a GraphQL endpoint atop an existing REST API, using JavaScript alone. +No backend developers will be harmed during the making of this blog post. ## A client-side REST wrapper -We're going to create a _GraphQL schema_ – a type system that describes your universe of data – that wraps calls to your existing REST API. This schema will receive and resolve GraphQL queries all on the client side. This architecture features some inherent performance flaws, but is fast to implement and requires no server changes. +We're going to create a _GraphQL schema_ – a type system that describes your +universe of data – that wraps calls to your existing REST API. This schema will +receive and resolve GraphQL queries all on the client side. This architecture +features some inherent performance flaws, but is fast to implement and requires +no server changes. -Imagine a REST API that exposes a `/people/` endpoint through which you can browse `Person` models and their associated friends. +Imagine a REST API that exposes a `/people/` endpoint through which you can +browse `Person` models and their associated friends. ![A REST API that exposes an index of people][rest-api-people] -We will build a GraphQL schema that models people and their attributes (like `first_name` and `email`) as well as their association to other people through friendships. +We will build a GraphQL schema that models people and their attributes (like +`first_name` and `email`) as well as their association to other people through +friendships. ### Installation @@ -29,35 +43,36 @@ npm i graphql ### Building the GraphQL Schema -Ultimately we will want to export a `GraphQLSchema` that we can use to resolve queries. +Ultimately we will want to export a `GraphQLSchema` that we can use to resolve +queries. ```js import { GraphQLSchema } from "graphql" export default new GraphQLSchema({ - query: QueryType, + query: QueryType }) ``` -At the root of all GraphQL schemas is a type called `query` whose definition we provide, and have specified here as `QueryType`. Let's build `QueryType` now – a type on which we will define all the possible things one might want to fetch. +At the root of all GraphQL schemas is a type called `query` whose definition we +provide, and have specified here as `QueryType`. Let's build `QueryType` now – a +type on which we will define all the possible things one might want to fetch. -To replicate all of the functionality of our REST API, let's expose two fields on `QueryType`: +To replicate all of the functionality of our REST API, let's expose two fields +on `QueryType`: - an `allPeople` field – analogous to `/people/` - a `person(id: String)` field – analogous to `/people/{ID}/` -Each field will consist of a return type, optional argument definitions, and a JavaScript method that resolves the data being queried for. +Each field will consist of a return type, optional argument definitions, and a +JavaScript method that resolves the data being queried for. ```js -import { - GraphQLList, - GraphQLObjectType, - GraphQLString, -} from 'graphql'; +import { GraphQLList, GraphQLObjectType, GraphQLString } from "graphql" const QueryType = new GraphQLObjectType({ - name: 'Query', - description: 'The root of all... queries', + name: "Query", + description: "The root of all... queries", fields: () => ({ allPeople: { type: new GraphQLList(PersonType), @@ -66,49 +81,57 @@ const QueryType = new GraphQLObjectType({ person: { type: PersonType, args: { - id: { type: GraphQLString }, + id: { type: GraphQLString } }, resolve: (root, args) => {} // Fetch the person with ID `args.id`, - }, - }), -}); + } + }) +}) ``` -Let's leave the resolvers as a sketch for now, and move on to defining `PersonType`. +Let's leave the resolvers as a sketch for now, and move on to defining +`PersonType`. ```js -import { - GraphQLList, - GraphQLObjectType, - GraphQLString, -} from 'graphql'; +import { GraphQLList, GraphQLObjectType, GraphQLString } from "graphql" const PersonType = new GraphQLObjectType({ - name: 'Person', - description: 'Somebody that you used to know', + name: "Person", + description: "Somebody that you used to know", fields: () => ({ firstName: { type: GraphQLString, - resolve: person => person.first_name, + resolve: person => person.first_name }, lastName: { type: GraphQLString, - resolve: person => person.last_name, + resolve: person => person.last_name }, - email: {type: GraphQLString}, - id: {type: GraphQLString}, - username: {type: GraphQLString}, + email: { type: GraphQLString }, + id: { type: GraphQLString }, + username: { type: GraphQLString }, friends: { type: new GraphQLList(PersonType), resolve: person => {} // Fetch the friends with the URLs `person.friends`, - }, - }), -}); + } + }) +}) ``` -Note two things about the definition of `PersonType`. Firstly, we have not supplied a resolver for `email`, `id`, or `username`. The default resolver simply accesses the property of the `person` object that has the same name as the field. This works everywhere except where the property names do not match the field name (eg. the field `firstName` does not match the `first_name` property of the response object from the REST API) or where accessing the property would not yield the object that we want (eg. we want a list of person objects for the `friends` field, not a list of URLs). - -Now, let's write resolvers that fetch people from the REST API. Because we need to load from the network, we won't be able to return a value right away. Luckily for us, `resolve()` can return either a value or a `Promise` for a value. We're going to take advantage of this to fire off an HTTP request to the REST API that eventually resolves to a JavaScript object that conforms to `PersonType`. +Note two things about the definition of `PersonType`. Firstly, we have not +supplied a resolver for `email`, `id`, or `username`. The default resolver +simply accesses the property of the `person` object that has the same name as +the field. This works everywhere except where the property names do not match +the field name (eg. the field `firstName` does not match the `first_name` +property of the response object from the REST API) or where accessing the +property would not yield the object that we want (eg. we want a list of person +objects for the `friends` field, not a list of URLs). + +Now, let's write resolvers that fetch people from the REST API. Because we need +to load from the network, we won't be able to return a value right away. Luckily +for us, `resolve()` can return either a value or a `Promise` for a value. We're +going to take advantage of this to fire off an HTTP request to the REST API that +eventually resolves to a JavaScript object that conforms to `PersonType`. And here we have it – a complete first-pass at the schema: @@ -117,21 +140,21 @@ import { GraphQLList, GraphQLObjectType, GraphQLSchema, - GraphQLString, -} from 'graphql'; + GraphQLString +} from "graphql" -const BASE_URL = 'https://myapp.com/'; +const BASE_URL = "https://myapp.com/" function fetchResponseByURL(relativeURL) { - return fetch(`${BASE_URL}${relativeURL}`).then(res => res.json()); + return fetch(`${BASE_URL}${relativeURL}`).then(res => res.json()) } function fetchPeople() { - return fetchResponseByURL('/people/').then(json => json.people); + return fetchResponseByURL("/people/").then(json => json.people) } function fetchPersonByURL(relativeURL) { - return fetchResponseByURL(relativeURL).then(json => json.person); + return fetchResponseByURL(relativeURL).then(json => json.person) } const PersonType = new GraphQLObjectType({ @@ -140,71 +163,90 @@ const PersonType = new GraphQLObjectType({ /* ... */ friends: { type: new GraphQLList(PersonType), - resolve: person => person.friends.map(fetchPersonByURL), - }, - }), -}); + resolve: person => person.friends.map(fetchPersonByURL) + } + }) +}) const QueryType = new GraphQLObjectType({ /* ... */ fields: () => ({ allPeople: { type: new GraphQLList(PersonType), - resolve: fetchPeople, + resolve: fetchPeople }, person: { type: PersonType, args: { - id: { type: GraphQLString }, + id: { type: GraphQLString } }, - resolve: (root, args) => fetchPersonByURL(`/people/${args.id}/`), - }, - }), -}); + resolve: (root, args) => fetchPersonByURL(`/people/${args.id}/`) + } + }) +}) export default new GraphQLSchema({ - query: QueryType, -}); + query: QueryType +}) ``` ### Using a client-side schema with Relay -Normally, Relay will send its GraphQL queries to a server over HTTP. We can inject [@taion](https://github.com/taion/)'s custom `relay-local-schema` network layer to resolve queries using the schema we just built. Put this code wherever it's guaranteed to be executed before you mount your Relay app. +Normally, Relay will send its GraphQL queries to a server over HTTP. We can +inject [@taion](https://github.com/taion/)'s custom `relay-local-schema` network +layer to resolve queries using the schema we just built. Put this code wherever +it's guaranteed to be executed before you mount your Relay app. ```sh npm2yarn npm i relay-local-schema ``` ```js -import RelayLocalSchema from 'relay-local-schema'; +import RelayLocalSchema from "relay-local-schema" -import schema from './schema'; +import schema from "./schema" -Relay.injectNetworkLayer( - new RelayLocalSchema.NetworkLayer({ schema }) -); +Relay.injectNetworkLayer(new RelayLocalSchema.NetworkLayer({ schema })) ``` -And that's that. Relay will send all of its queries to your custom client-resident schema, which will in turn resolve them by making calls to your existing REST API. +And that's that. Relay will send all of its queries to your custom +client-resident schema, which will in turn resolve them by making calls to your +existing REST API. ## A server-side REST wrapper -The client-side REST API wrapper demonstrated above should help you get up and running quickly so that you can try out a Relay version of your app (or part of your app). +The client-side REST API wrapper demonstrated above should help you get up and +running quickly so that you can try out a Relay version of your app (or part of +your app). -However, as we mentioned before, this architecture features some inherent performance flaws because of how GraphQL is still calling your underlying REST API which can be very network intensive. A good next step is to move the schema from the client side to the server side to minimize latency on the network and to give you more power to cache responses. +However, as we mentioned before, this architecture features some inherent +performance flaws because of how GraphQL is still calling your underlying REST +API which can be very network intensive. A good next step is to move the schema +from the client side to the server side to minimize latency on the network and +to give you more power to cache responses. -Take the next 10 minutes to watch me build a server side version of the GraphQL wrapper above using Node and Express. +Take the next 10 minutes to watch me build a server side version of the GraphQL +wrapper above using Node and Express. -