@ikkan/core
Base functionalities for Ikkan
Introduction
This package contains utils and types that are used by the other packages in the Ikkan ecosystem.
It mainly exposes the ikkanConfig
function, which is used to configure the API.
An API endpoint is reduced to a few basic properties:
- endpoint: The URL of the endpoint. Because Next.js supports dynamic routes, a simple
string
is not enough. In Ikkan, this is represented a function that can have params (according to the Next.js dynamic routes syntax) and that will return the URL of the endpoint. - method: The HTTP method of the endpoint. It can be any of the HTTP methods supported by the browser, except for
HEAD
, which is too specific to be supported by Ikkan. - schema: The schema of the data that the endpoint will accept. It is a Zod schema, which is a type-safe way to validate data.
- fn: The function that will be called when the endpoint is hit. It is an `async function that will receive the request object and the params of the endpoint, and that will return the data that will be sent to the client.
Because Ikkan is designed to be used with TypeScript, all these properties are type-safe, meaning that you will be told if you pass the wrong arguments to a function, and you will know what to expect from the return value.
You also won't have to define much types, because ikkanConfig
will infer the types of the properties from the object you pass to it.
Types
type: IkkanConfig
Prop | Type | Default |
---|---|---|
endpoint | (() => string) | ((segments: Record<string, string, string[]>) => string) | - |
method | GET | POST | PUT | DELETE | PATCH | OPTIONS | - |
schema | ZodType<any, any, any> | undefined | undefined |
ssi | (() => Promise<any>) | undefined | undefined |
fn | IkkanHandler | - |
Considerations:
- endpoint: If you decide to use dynamic route, you will have to type the
args
parameter of theendpoint
function, as Typescript cannot infer if the values are supposed to be strings or arrays of strings.
❗ Be careful with that argument, as it is the only one that will not raise error if improperly configured. - ssi: This property is used to import data dynamically. Because the config object may be used by client-side code, server-side only imports cannot be declaratively defined. In order not to import them every time the endpoint is called, this function will only run once, when the endpoint is first compiled, and its result will be passed to
fn
.
type: IkkanHandler
As you have noticed, there are three properties that can be undefined in the IkkanConfig
type: schema: Schema
, ssi: ServerSideImports
and the args of the endpoint
function ((segments: EndpointArgs) => string
). This will result in the IkkanHandler
type being a bit more complex than you would expect.
Depending on how these properties are defined or not, the fn
function will have different parameters:
Schema | EndpointArgs | ServerSideImports | fn |
---|---|---|---|
❌ | ❌ | ❌ | async (req: NextRequest) => Promise<Output> |
❌ | ❌ | ✅ | async (req: NextRequest, imports: Awaited<ReturnType<ServerSideImports>>) => Promise<Output> |
✅ | ❌ | ❌ | async (req: NextRequest, params: z.infer<Schema>) => Promise<Output> |
✅ | ❌ | ✅ | async (req: NextRequest, params: z.infer<Schema>, imports: Awaited<ReturnType<ServerSideImports>>) => Promise<Output> |
❌ | ✅ | ❌ | async (req: NextRequest, segments: NextDynamicSegments<EndpointArgs>) => Promise<Output> |
❌ | ✅ | ✅ | async (req: NextRequest, segments: NextDynamicSegments<EndpointArgs>, imports: Awaited<ReturnType<ServerSideImports>>) => Promise<Output> |
✅ | ✅ | ❌ | async (req: NextRequest, params: z.infer<Schema>, segments: NextDynamicSegments<EndpointArgs>) => Promise<Output> |
✅ | ✅ | ✅ | async (req: NextRequest, params: z.infer<Schema>, segments: NextDynamicSegments<EndpointArgs>, imports: Awaited<ReturnType<ServerSideImports>>) => Promise<Output> |
ikkanConfig
This function simply allows Typescript to automatically infer the types of the properties of the object you pass to it.
Pass it an object with the properties of the IkkanConfig
type, and it will return an object with the same properties, but with the types inferred.
In this example, config is inferred as :